From 467ce343680c60bb9d7a368f06ef3b3ca428a7e9 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Fri, 9 Jan 2015 15:13:36 +0100 Subject: [PATCH 01/16] Improve config tests [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I6fc7974d3379d4a96aa712e3e00b8798e6d90181 --- tests/unit_tests/config/testconfig-example.hpp | 12 ++++ tests/unit_tests/config/ut-configuration.cpp | 96 ++++++++++++++++++++++---- tests/unit_tests/config/ut-dynvisit.cpp | 17 ++--- tests/unit_tests/config/ut-kvstore.cpp | 16 ++--- 4 files changed, 112 insertions(+), 29 deletions(-) diff --git a/tests/unit_tests/config/testconfig-example.hpp b/tests/unit_tests/config/testconfig-example.hpp index 35e846e..c8563d0 100644 --- a/tests/unit_tests/config/testconfig-example.hpp +++ b/tests/unit_tests/config/testconfig-example.hpp @@ -122,6 +122,18 @@ struct TestConfig { ) }; +struct PartialTestConfig { + // a subset of TestConfig fields + std::string stringVal; + std::vector intVector; + + CONFIG_REGISTER + ( + stringVal, + intVector + ) +}; + /** * JSON string used in ConfigSuite test cases * For the purpose of these tests the order of this string diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index bbf9ed9..e014f68 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -27,19 +27,30 @@ #include "ut.hpp" #include "testconfig-example.hpp" #include "config/manager.hpp" +#include "utils/scoped-dir.hpp" #include #include #include -#include -namespace fs = boost::filesystem; +namespace { + using namespace config; -BOOST_AUTO_TEST_SUITE(ConfigurationSuite) +const std::string UT_PATH = "/tmp/ut-config/"; +const std::string DB_PATH = UT_PATH + "kvstore.db3"; +const std::string DB_PREFIX = "ut"; // Floating point tolerance as a number of rounding errors const int TOLERANCE = 1; +struct Fixture { + vasum::utils::ScopedDir mUTDirGuard; + Fixture() : mUTDirGuard(UT_PATH) {} +}; + +} // namespace + +BOOST_FIXTURE_TEST_SUITE(ConfigurationSuite, Fixture) BOOST_AUTO_TEST_CASE(FromStringTest) { @@ -249,17 +260,12 @@ BOOST_AUTO_TEST_CASE(FromToKVStoreTest) TestConfig config; loadFromJsonString(jsonTestString, config); - std::string dbPath = fs::unique_path("/tmp/kvstore-%%%%.db3").string(); - - saveToKVStore(dbPath, config, "prefix"); + saveToKVStore(DB_PATH, config, DB_PREFIX); TestConfig outConfig; - loadFromKVStore(dbPath, outConfig, "prefix"); + loadFromKVStore(DB_PATH, outConfig, DB_PREFIX); std::string out = saveToJsonString(outConfig); BOOST_CHECK_EQUAL(out, jsonTestString); - - fs::remove(dbPath); - fs::remove(dbPath + "-journal"); } BOOST_AUTO_TEST_CASE(FromToFDTest) @@ -267,7 +273,7 @@ BOOST_AUTO_TEST_CASE(FromToFDTest) TestConfig config; loadFromJsonString(jsonTestString, config); // Setup fd - std::string fifoPath = fs::unique_path("/tmp/fdstore-%%%%").string(); + std::string fifoPath = UT_PATH + "fdstore"; BOOST_CHECK(::mkfifo(fifoPath.c_str(), S_IWUSR | S_IRUSR) >= 0); int fd = ::open(fifoPath.c_str(), O_RDWR); BOOST_REQUIRE(fd >= 0); @@ -281,7 +287,73 @@ BOOST_AUTO_TEST_CASE(FromToFDTest) // Cleanup BOOST_CHECK(::close(fd) >= 0); - fs::remove(fifoPath); +} + +BOOST_AUTO_TEST_CASE(FromKVWithDefaultsTest) +{ + TestConfig config; + loadFromJsonString(jsonTestString, config); + + // nothing in db + TestConfig outConfig1; + loadFromKVStoreWithJson(DB_PATH, jsonTestString, outConfig1, DB_PREFIX); + + std::string out1 = saveToJsonString(outConfig1); + BOOST_CHECK_EQUAL(out1, jsonTestString); + + // all in db + saveToKVStore(DB_PATH, config, DB_PREFIX); + TestConfig outConfig2; + outConfig2.union1.set(0); + outConfig2.union2.set(0); + std::string emptyConfig = saveToJsonString(outConfig2); + loadFromKVStoreWithJson(DB_PATH, emptyConfig, outConfig2, DB_PREFIX); + + std::string out2 = saveToJsonString(outConfig2); + BOOST_CHECK_EQUAL(out2, jsonTestString); +} + +BOOST_AUTO_TEST_CASE(PartialConfigTest) +{ + // check if partial config is fully supported + TestConfig config; + loadFromJsonString(jsonTestString, config); + + // from string + { + PartialTestConfig partialConfig; + loadFromJsonString(jsonTestString, partialConfig); + + BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal); + BOOST_CHECK(config.intVector == partialConfig.intVector); + } + + // from kv + { + PartialTestConfig partialConfig; + saveToKVStore(DB_PATH, config, DB_PREFIX); + loadFromKVStore(DB_PATH, partialConfig, DB_PREFIX); + + BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal); + BOOST_CHECK(config.intVector == partialConfig.intVector); + } + + // from kv with defaults + { + PartialTestConfig partialConfig; + loadFromKVStoreWithJson(DB_PATH, jsonTestString, partialConfig, DB_PREFIX); + + BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal); + BOOST_CHECK(config.intVector == partialConfig.intVector); + } + + // save to kv + { + PartialTestConfig partialConfig; + partialConfig.stringVal = "partial"; + partialConfig.intVector = {7}; + config::saveToKVStore(DB_PATH, partialConfig, DB_PREFIX); + } } BOOST_AUTO_TEST_CASE(ConfigUnionTest) diff --git a/tests/unit_tests/config/ut-dynvisit.cpp b/tests/unit_tests/config/ut-dynvisit.cpp index dd782f3..2050def 100644 --- a/tests/unit_tests/config/ut-dynvisit.cpp +++ b/tests/unit_tests/config/ut-dynvisit.cpp @@ -26,31 +26,32 @@ #include "config.hpp" #include "ut.hpp" #include "testconfig-example.hpp" +#include "utils/scoped-dir.hpp" #include "config/manager.hpp" -#include #include "config/from-kvjson-visitor.hpp" +namespace { using namespace config; -namespace fs = boost::filesystem; + +const std::string UT_PATH = "/tmp/ut-config/"; struct Fixture { + vasum::utils::ScopedDir mUTDirGuard; std::string dbPath; std::string dbPrefix; Fixture() - : dbPath(fs::unique_path("/tmp/kvstore-%%%%.db3").string()) + : mUTDirGuard(UT_PATH) + , dbPath(UT_PATH + "kvstore.db3") , dbPrefix("conf") { - fs::remove(dbPath); - } - ~Fixture() - { - fs::remove(dbPath); } }; +} // namespace + BOOST_FIXTURE_TEST_SUITE(DynVisitSuite, Fixture) void checkJsonConfig(const TestConfig& cfg, const std::string& json) diff --git a/tests/unit_tests/config/ut-kvstore.cpp b/tests/unit_tests/config/ut-kvstore.cpp index ba95452..9855457 100644 --- a/tests/unit_tests/config/ut-kvstore.cpp +++ b/tests/unit_tests/config/ut-kvstore.cpp @@ -28,6 +28,7 @@ #include "config/kvstore.hpp" #include "config/exception.hpp" +#include "utils/scoped-dir.hpp" #include #include @@ -38,19 +39,18 @@ namespace fs = boost::filesystem; namespace { +const std::string UT_PATH = "/tmp/ut-config/"; + struct Fixture { + vasum::utils::ScopedDir mUTDirGuard; std::string dbPath; KVStore c; Fixture() - : dbPath(fs::unique_path("/tmp/kvstore-%%%%.db3").string()), - c(dbPath) - { - } - ~Fixture() + : mUTDirGuard(UT_PATH) + , dbPath(UT_PATH + "kvstore.db3") + , c(dbPath) { - fs::remove(dbPath); - fs::remove(dbPath + "-journal"); } }; @@ -97,7 +97,6 @@ const std::string KEY = "KEY"; BOOST_AUTO_TEST_CASE(SimpleConstructorDestructorTest) { - const std::string dbPath = fs::unique_path("/tmp/kvstore-%%%%.db3").string(); std::unique_ptr conPtr; BOOST_REQUIRE_NO_THROW(conPtr.reset(new KVStore(dbPath))); BOOST_CHECK(fs::exists(dbPath)); @@ -105,7 +104,6 @@ BOOST_AUTO_TEST_CASE(SimpleConstructorDestructorTest) BOOST_CHECK(fs::exists(dbPath)); BOOST_REQUIRE_NO_THROW(conPtr.reset()); BOOST_CHECK(fs::exists(dbPath)); - fs::remove(dbPath); } BOOST_AUTO_TEST_CASE(EscapedCharactersTest) -- 2.7.4 From 8d508112b8644e21a065307b3bff7a4c93162234 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 22 Jan 2015 12:51:04 +0100 Subject: [PATCH 02/16] Fix LxcZoneSuite/StartStopTest [Bug/Feature] Test was failing [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: Ia87dbd173cfe58f216adac1141a15d854e91159c --- tests/unit_tests/lxc/ut-zone.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit_tests/lxc/ut-zone.cpp b/tests/unit_tests/lxc/ut-zone.cpp index b80e261..6840e31 100644 --- a/tests/unit_tests/lxc/ut-zone.cpp +++ b/tests/unit_tests/lxc/ut-zone.cpp @@ -138,8 +138,11 @@ BOOST_AUTO_TEST_CASE(StartStopTest) }; BOOST_CHECK(lxc.start(argv)); BOOST_CHECK(lxc.getState() == LxcZone::State::RUNNING); + waitForInit(); +#ifndef USE_EXEC // TODO improve shutdown implementation BOOST_CHECK(!lxc.shutdown(1)); BOOST_CHECK(lxc.getState() == LxcZone::State::RUNNING); +#endif BOOST_CHECK(lxc.stop()); BOOST_CHECK(lxc.getState() == LxcZone::State::STOPPED); -- 2.7.4 From ca9543ec62d3c1295677758be5df99cad79085e0 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 22 Jan 2015 09:34:38 +0100 Subject: [PATCH 03/16] Provisioning uses dynamic configuration [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: If1762b8d0993a98048d2f9310981c53f2a913124 --- server/configs/templates/template.conf | 1 + server/zone-provision-config.hpp | 8 +- server/zone-provision.cpp | 98 +++++------ server/zone-provision.hpp | 38 ++-- server/zone.cpp | 11 +- server/zone.hpp | 2 + server/zones-manager.cpp | 3 +- server/zones-manager.hpp | 2 +- .../configs/ut-client/zones/console1-dbus.conf.in | 1 + .../configs/ut-client/zones/console2-dbus.conf.in | 1 + .../configs/ut-client/zones/console3-dbus.conf.in | 1 + tests/unit_tests/server/configs/CMakeLists.txt | 5 + .../server/configs/ut-server/zones/zone1.conf | 1 + .../server/configs/ut-server/zones/zone2.conf | 1 + .../server/configs/ut-server/zones/zone3.conf | 1 + .../server/configs/ut-zone-admin/zones/buggy.conf | 1 + .../configs/ut-zone-admin/zones/missing.conf | 1 + .../ut-zone-admin/zones/test-no-shutdown.conf | 1 + .../server/configs/ut-zone-admin/zones/test.conf | 1 + .../server/configs/ut-zone-provision/test.conf | 3 + .../server/configs/ut-zone/zones/buggy.conf | 1 + .../server/configs/ut-zone/zones/test-dbus.conf.in | 1 + .../server/configs/ut-zone/zones/test.conf | 1 + .../ut-zones-manager/templates/template.conf.in | 1 + .../ut-zones-manager/zones/console1-dbus.conf.in | 1 + .../configs/ut-zones-manager/zones/console1.conf | 1 + .../ut-zones-manager/zones/console2-dbus.conf.in | 1 + .../configs/ut-zones-manager/zones/console2.conf | 1 + .../ut-zones-manager/zones/console3-dbus.conf.in | 1 + .../configs/ut-zones-manager/zones/console3.conf | 1 + tests/unit_tests/server/ut-zone-provision.cpp | 196 ++++++++++++--------- tests/unit_tests/server/ut-zone.cpp | 2 + 32 files changed, 225 insertions(+), 164 deletions(-) create mode 100644 tests/unit_tests/server/configs/ut-zone-provision/test.conf diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf index e011a64..9690a87 100644 --- a/server/configs/templates/template.conf +++ b/server/configs/templates/template.conf @@ -11,6 +11,7 @@ "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "runMountPoint" : "~NAME~/run", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [ "/tmp/", diff --git a/server/zone-provision-config.hpp b/server/zone-provision-config.hpp index 5a9f5ff..93fe1a0 100644 --- a/server/zone-provision-config.hpp +++ b/server/zone-provision-config.hpp @@ -34,7 +34,7 @@ namespace vasum { -struct ZoneProvisioning +struct ZoneProvisioningConfig { struct File @@ -83,7 +83,7 @@ struct ZoneProvisioning ) }; - struct Unit + struct Provision { CONFIG_DECLARE_UNION ( @@ -93,11 +93,11 @@ struct ZoneProvisioning ) }; - std::vector units; + std::vector provisions; CONFIG_REGISTER ( - units + provisions ) }; diff --git a/server/zone-provision.cpp b/server/zone-provision.cpp index c04a32a..928d887 100644 --- a/server/zone-provision.cpp +++ b/server/zone-provision.cpp @@ -42,29 +42,17 @@ namespace fs = boost::filesystem; namespace vasum { -namespace { - -const std::string ZONE_PROVISION_FILE = "provision.conf"; - -void declareUnit(const std::string& file, ZoneProvisioning::Unit&& unit) -{ - // TODO: Add to the dynamic configuration - ZoneProvisioning config; - if (fs::exists(file)) { - config::loadFromJsonFile(file, config); - } - config.units.push_back(std::move(unit)); - config::saveToJsonFile(file, config); -} - -} // namespace - -ZoneProvision::ZoneProvision(const std::string& zonePath, +ZoneProvision::ZoneProvision(const std::string& rootPath, + const std::string& configPath, + const std::string& dbPath, + const std::string& dbPrefix, const std::vector& validLinkPrefixes) + : mRootPath(rootPath) + , mDbPath(dbPath) + , mDbPrefix(dbPrefix) + , mValidLinkPrefixes(validLinkPrefixes) { - mProvisionFile = (fs::path(zonePath) / fs::path(ZONE_PROVISION_FILE)).string(); - mRootPath = (zonePath / fs::path("rootfs")).string(); - mValidLinkPrefixes = validLinkPrefixes; + config::loadFromKVStoreWithJsonFile(dbPath, configPath, mProvisioningConfig, dbPrefix); } ZoneProvision::~ZoneProvision() @@ -72,21 +60,26 @@ ZoneProvision::~ZoneProvision() stop(); } -std::string ZoneProvision::getRootPath() const +void ZoneProvision::saveProvisioningConfig() { - return mRootPath; + config::saveToKVStore(mDbPath, mProvisioningConfig, mDbPrefix); } +void ZoneProvision::declareProvision(ZoneProvisioningConfig::Provision&& provision) +{ + mProvisioningConfig.provisions.push_back(std::move(provision)); + saveProvisioningConfig(); +} void ZoneProvision::declareFile(const int32_t& type, const std::string& path, const int32_t& flags, const int32_t& mode) { - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::File({type, path, flags, mode})); + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::File({type, path, flags, mode})); - declareUnit(mProvisionFile, std::move(unit)); + declareProvision(std::move(provision)); } void ZoneProvision::declareMount(const std::string& source, @@ -95,49 +88,46 @@ void ZoneProvision::declareMount(const std::string& source, const int64_t& flags, const std::string& data) { - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::Mount({source, target, type, flags, data})); + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::Mount({source, target, type, flags, data})); - declareUnit(mProvisionFile, std::move(unit)); + declareProvision(std::move(provision)); } void ZoneProvision::declareLink(const std::string& source, const std::string& target) { - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::Link({source, target})); + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::Link({source, target})); - declareUnit(mProvisionFile, std::move(unit)); + declareProvision(std::move(provision)); } void ZoneProvision::start() noexcept { - if (fs::exists(mProvisionFile)) { - config::loadFromJsonFile(mProvisionFile, mProvisioningConfig); - for (const auto& unit : mProvisioningConfig.units) { - try { - if (unit.is()) { - file(unit.as()); - } else if (unit.is()) { - mount(unit.as()); - } else if (unit.is()) { - link(unit.as()); - } - // mProvisioned must be FILO - mProvisioned.push_front(unit); - } catch (const std::exception& ex) { - LOGE("Provsion error: " << ex.what()); + for (const auto& provision : mProvisioningConfig.provisions) { + try { + if (provision.is()) { + file(provision.as()); + } else if (provision.is()) { + mount(provision.as()); + } else if (provision.is()) { + link(provision.as()); } + // mProvisioned must be FILO + mProvisioned.push_front(provision); + } catch (const std::exception& ex) { + LOGE("Provsion error: " << ex.what()); } } } void ZoneProvision::stop() noexcept { - mProvisioned.remove_if([this](const ZoneProvisioning::Unit& unit) -> bool { + mProvisioned.remove_if([this](const ZoneProvisioningConfig::Provision& provision) -> bool { try { - if (unit.is()) { - umount(unit.as()); + if (provision.is()) { + umount(provision.as()); } // leaves files, links, fifo, untouched return true; @@ -148,7 +138,7 @@ void ZoneProvision::stop() noexcept }); } -void ZoneProvision::file(const ZoneProvisioning::File& config) +void ZoneProvision::file(const ZoneProvisioningConfig::File& config) { bool ret = false; const fs::path hostPath = fs::path(mRootPath) / fs::path(config.path); @@ -183,7 +173,7 @@ void ZoneProvision::file(const ZoneProvisioning::File& config) } } -void ZoneProvision::mount(const ZoneProvisioning::Mount& config) +void ZoneProvision::mount(const ZoneProvisioningConfig::Mount& config) { const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target); bool ret = utils::mount(config.source, @@ -196,7 +186,7 @@ void ZoneProvision::mount(const ZoneProvisioning::Mount& config) } } -void ZoneProvision::umount(const ZoneProvisioning::Mount& config) +void ZoneProvision::umount(const ZoneProvisioningConfig::Mount& config) { const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target); bool ret = utils::umount(hostPath.string()); @@ -205,7 +195,7 @@ void ZoneProvision::umount(const ZoneProvisioning::Mount& config) } } -void ZoneProvision::link(const ZoneProvisioning::Link& config) +void ZoneProvision::link(const ZoneProvisioningConfig::Link& config) { const std::string srcHostPath = fs::path(config.source).normalize().string(); for (const std::string& prefix : mValidLinkPrefixes) { diff --git a/server/zone-provision.hpp b/server/zone-provision.hpp index 5585c1f..f6933db 100644 --- a/server/zone-provision.hpp +++ b/server/zone-provision.hpp @@ -44,12 +44,23 @@ class ZoneProvision { public: /** * ZoneProvision constructor - * @param zonePath directory where zones are defined (lxc configs, rootfs etc) + * @param rootPath zone root path + * @param configPath path to config with defaults + * @param dbPath path to database + * @param dbPrefix database prefix + * @param validLinkPrefixes valid link prefixes */ - ZoneProvision(const std::string& zonePath, + ZoneProvision(const std::string& rootPath, + const std::string& configPath, + const std::string& dbPath, + const std::string& dbPrefix, const std::vector& validLinkPrefixes); ~ZoneProvision(); + ZoneProvision(const ZoneProvision&) = delete; + ZoneProvision& operator=(const ZoneProvision&) = delete; + ZoneProvision(ZoneProvision&&) = default; + /** * Declare file, directory or pipe that will be created while zone startup */ @@ -71,25 +82,24 @@ public: void declareLink(const std::string& source, const std::string& target); - /** - * Get zone root path - */ - std::string getRootPath() const; - void start() noexcept; void stop() noexcept; private: - ZoneProvisioning mProvisioningConfig; + ZoneProvisioningConfig mProvisioningConfig; std::string mRootPath; - std::string mProvisionFile; + std::string mDbPath; + std::string mDbPrefix; std::vector mValidLinkPrefixes; - std::list mProvisioned; + std::list mProvisioned; + + void saveProvisioningConfig(); + void declareProvision(ZoneProvisioningConfig::Provision&& provision); - void mount(const ZoneProvisioning::Mount& config); - void umount(const ZoneProvisioning::Mount& config); - void file(const ZoneProvisioning::File& config); - void link(const ZoneProvisioning::Link& config); + void mount(const ZoneProvisioningConfig::Mount& config); + void umount(const ZoneProvisioningConfig::Mount& config); + void file(const ZoneProvisioningConfig::File& config); + void link(const ZoneProvisioningConfig::Link& config); }; diff --git a/server/zone.cpp b/server/zone.cpp index f35a360..fbbd819 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -48,12 +48,14 @@ typedef std::lock_guard Lock; // TODO: move constants to the config file when default values are implemented there const int RECONNECT_RETRIES = 15; const int RECONNECT_DELAY = 1 * 1000; +const std::string DB_PREFIX = "zone."; } // namespace Zone::Zone(const utils::Worker::Pointer& worker, const std::string& zonesPath, const std::string& zoneConfigPath, + const std::string& dbPath, const std::string& lxcTemplatePrefix, const std::string& baseRunMountPointPath) : mWorker(worker) @@ -72,8 +74,12 @@ Zone::Zone(const utils::Worker::Pointer& worker, } mAdmin.reset(new ZoneAdmin(zonesPath, lxcTemplatePrefix, mConfig)); + const fs::path zonePath = fs::path(zonesPath) / mAdmin->getId(); - mProvision.reset(new ZoneProvision(zonePath.string(), mConfig.validLinkPrefixes)); + mRootPath = (zonePath / fs::path("rootfs")).string(); + const std::string dbPrefix = DB_PREFIX + mAdmin->getId(); + + mProvision.reset(new ZoneProvision(mRootPath, zoneConfigPath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); } Zone::~Zone() @@ -185,10 +191,9 @@ int Zone::getVT() const std::string Zone::getRootPath() const { - return mProvision->getRootPath(); + return mRootPath; } - bool Zone::activateVT() { Lock lock(mReconnectMutex); diff --git a/server/zone.hpp b/server/zone.hpp index 7eb34cf..2eab7f3 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -55,6 +55,7 @@ public: Zone(const utils::Worker::Pointer& worker, const std::string& zonesPath, const std::string& zoneConfigPath, + const std::string& dbPath, const std::string& lxcTemplatePrefix, const std::string& baseRunMountPointPath); Zone(Zone&&) = default; @@ -269,6 +270,7 @@ private: DbusStateChangedCallback mDbusStateChangedCallback; std::string mDbusAddress; std::string mRunMountPoint; + std::string mRootPath; void onNameLostCallback(); void reconnectHandler(); diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index f65f9e3..99e87ee 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -204,6 +204,7 @@ void ZonesManager::createZone(const std::string& zoneConfigPath) std::unique_ptr zone(new Zone(mWorker->createSubWorker(), mConfig.zonesPath, zoneConfigPath, + mConfig.dbPath, mConfig.lxcTemplatePrefix, mConfig.runMountPointPrefix)); const std::string id = zone->getId(); @@ -254,7 +255,7 @@ void ZonesManager::destroyZone(const std::string& zoneId) it->second->setDestroyOnExit(); mZones.erase(it); - if (mZones.size() == 0) { + if (mZones.empty()) { if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME))) { LOGE("Failed to remove enabled file."); } diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index e074fc9..677b056 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -50,7 +50,7 @@ public: /** * Create new zone. * - * @param zoneConfig config of new zone + * @param zoneConfigPath config of new zone */ void createZone(const std::string& zoneConfigPath); diff --git a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in index 46fb716..097480d 100644 --- a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in +++ b/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*", "/etc/secret2" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in index 260d01f..440772b 100644 --- a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in +++ b/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in index e20ffe9..2f28ee1 100644 --- a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in +++ b/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index 4a9edbe..596c123 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -28,6 +28,8 @@ FILE(GLOB manager_zone_CONF ut-zones-manager/zones/*.conf) FILE(GLOB zone_CONF ut-zone/*.conf) FILE(GLOB zone_zone_CONF ut-zone/zones/*.conf) +FILE(GLOB zone_provision_CONF ut-zone-provision/*.conf) + FILE(GLOB admin_zone_CONF ut-zone-admin/zones/*.conf) FILE(GLOB connection_CONF ut-zone-connection/*.conf) @@ -97,6 +99,9 @@ INSTALL(FILES ${zone_zone_CONF} INSTALL(FILES ${zone_zone_CONF_GEN} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone/zones) +INSTALL(FILES ${zone_provision_CONF} + DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-provision) + INSTALL(FILES ${admin_zone_CONF} DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/server/ut-zone-admin/zones) diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf b/tests/unit_tests/server/configs/ut-server/zones/zone1.conf index 2c2ccde..432adc6 100644 --- a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf +++ b/tests/unit_tests/server/configs/ut-server/zones/zone1.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf b/tests/unit_tests/server/configs/ut-server/zones/zone2.conf index 1d500a7..2126b8f 100644 --- a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf +++ b/tests/unit_tests/server/configs/ut-server/zones/zone2.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf b/tests/unit_tests/server/configs/ut-server/zones/zone3.conf index a9856c7..dfc4a04 100644 --- a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf +++ b/tests/unit_tests/server/configs/ut-server/zones/zone3.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf index e96dca8..fa7bd6b 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf index 9a5ec68..5cb9524 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf index be05697..7ab5df7 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf index 45213d7..215fa4f 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone-provision/test.conf b/tests/unit_tests/server/configs/ut-zone-provision/test.conf new file mode 100644 index 0000000..504b486 --- /dev/null +++ b/tests/unit_tests/server/configs/ut-zone-provision/test.conf @@ -0,0 +1,3 @@ +{ + "provisions" : [] +} diff --git a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf index eaf0811..d29993c 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in index e4a18fa..77a4180 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zone-test-dbus", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test.conf b/tests/unit_tests/server/configs/ut-zone/zones/test.conf index 4386c8c..9887e1c 100644 --- a/tests/unit_tests/server/configs/ut-zone/zones/test.conf +++ b/tests/unit_tests/server/configs/ut-zone/zones/test.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [], "permittedToRecv" : [], "validLinkPrefixes" : [ "/tmp" ] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in index 7c2f5e4..28879db 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/~NAME~", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in index 46fb716..097480d 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*", "/etc/secret2" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf index 41071ad..1fd4061 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in index 260d01f..440772b 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf index f152092..3c37313 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in index e20ffe9..2f28ee1 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf index 4979dd2..8e54fe6 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf @@ -11,6 +11,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "", + "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] diff --git a/tests/unit_tests/server/ut-zone-provision.cpp b/tests/unit_tests/server/ut-zone-provision.cpp index 8d1738f..c488c09 100644 --- a/tests/unit_tests/server/ut-zone-provision.cpp +++ b/tests/unit_tests/server/ut-zone-provision.cpp @@ -28,6 +28,7 @@ #include "utils/scoped-dir.hpp" #include "utils/exception.hpp" +#include "utils/fs.hpp" #include "config/manager.hpp" #include "zone-provision.hpp" #include "zone-provision-config.hpp" @@ -47,13 +48,15 @@ namespace fs = boost::filesystem; namespace { -const std::string PROVISON_CONFIG_FILE = "provision.conf"; +const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone-provision/test.conf"; const std::string ZONE = "ut-zone-provision-test"; const fs::path ZONES_PATH = "/tmp/ut-zones"; const fs::path LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; const fs::path ZONE_PATH = ZONES_PATH / fs::path(ZONE); -const fs::path PROVISION_FILE_PATH = ZONE_PATH / fs::path(PROVISON_CONFIG_FILE); -const fs::path ROOTFS_PATH = ZONE_PATH / fs::path("rootfs"); +const fs::path SOME_FILE_PATH = ZONE_PATH / "file.txt"; +const fs::path ROOTFS_PATH = ZONE_PATH / "rootfs"; +const fs::path DB_PATH = ZONES_PATH / "vasum.db"; +const std::string DB_PREFIX = "zone"; struct Fixture { utils::ScopedDir mZonesPathGuard; @@ -63,6 +66,26 @@ struct Fixture { : mZonesPathGuard(ZONES_PATH.string()) , mRootfsPath(ROOTFS_PATH.string()) { + BOOST_REQUIRE(utils::saveFileContent(SOME_FILE_PATH.string(), "text")); + } + + ZoneProvision create(const std::vector& validLinkPrefixes) + { + return ZoneProvision(ROOTFS_PATH.string(), + TEST_CONFIG_PATH, + DB_PATH.string(), + DB_PREFIX, + validLinkPrefixes); + } + + void load(ZoneProvisioningConfig& config) + { + config::loadFromKVStoreWithJsonFile(DB_PATH.string(), TEST_CONFIG_PATH, config, DB_PREFIX); + } + + void save(const ZoneProvisioningConfig& config) + { + config::saveToKVStore(DB_PATH.string(), config, DB_PREFIX); } }; @@ -78,22 +101,22 @@ BOOST_AUTO_TEST_CASE(DestructorTest) { utils::ScopedDir provisionfs(mountSource.string()); - ZoneProvisioning config; - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY, + ZoneProvisioningConfig config; + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::File({VSMFILE_DIRECTORY, mountTarget.string(), 0, 0777})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::Mount({mountSource.string(), + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::Mount({mountSource.string(), mountTarget.string(), "", MS_BIND, ""})); - config.units.push_back(unit); + config.provisions.push_back(provision); + save(config); - config::saveToJsonFile(PROVISION_FILE_PATH.string(), config); - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.start(); } BOOST_CHECK(!fs::exists(mountSource)); @@ -103,35 +126,35 @@ BOOST_AUTO_TEST_CASE(FileTest) { //TODO: Test Fifo const fs::path regularFile = fs::path("/opt/usr/data/ut-regular-file"); - const fs::path copyFile = PROVISION_FILE_PATH; + const fs::path copyFile = SOME_FILE_PATH; - ZoneProvisioning config; - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY, + ZoneProvisioningConfig config; + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::File({VSMFILE_DIRECTORY, regularFile.parent_path().string(), 0, 0777})); - config.units.push_back(unit); + config.provisions.push_back(provision); - unit.set(ZoneProvisioning::File({VSMFILE_REGULAR, + provision.set(ZoneProvisioningConfig::File({VSMFILE_REGULAR, regularFile.string(), O_CREAT, 0777})); - config.units.push_back(unit); + config.provisions.push_back(provision); - unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY, + provision.set(ZoneProvisioningConfig::File({VSMFILE_DIRECTORY, copyFile.parent_path().string(), 0, 0777})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::File({VSMFILE_REGULAR, + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::File({VSMFILE_REGULAR, copyFile.string(), 0, 0777})); - config.units.push_back(unit); - config::saveToJsonFile(PROVISION_FILE_PATH.string(), config); + config.provisions.push_back(provision); + save(config); - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.start(); BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile.parent_path())); @@ -152,27 +175,27 @@ BOOST_AUTO_TEST_CASE(MountTest) utils::ScopedDir provisionfs(mountSource.string()); - ZoneProvisioning config; - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY, + ZoneProvisioningConfig config; + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::File({VSMFILE_DIRECTORY, mountTarget.string(), 0, 0777})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::Mount({mountSource.string(), + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::Mount({mountSource.string(), mountTarget.string(), "", MS_BIND, ""})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::File({VSMFILE_REGULAR, + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::File({VSMFILE_REGULAR, (mountTarget / sharedFile).string(), O_CREAT, 0777})); - config.units.push_back(unit); - config::saveToJsonFile(PROVISION_FILE_PATH.string(), config); + config.provisions.push_back(provision); + save(config); - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.start(); BOOST_CHECK(fs::exists(ROOTFS_PATH / mountTarget)); @@ -184,17 +207,17 @@ BOOST_AUTO_TEST_CASE(MountTest) BOOST_AUTO_TEST_CASE(LinkTest) { - const fs::path linkFile = fs::path("/ut-from-host-provision.conf"); + const fs::path linkFile = fs::path("/ut-from-host-file.txt"); - ZoneProvisioning config; - ZoneProvisioning::Unit unit; + ZoneProvisioningConfig config; + ZoneProvisioningConfig::Provision provision; - unit.set(ZoneProvisioning::Link({PROVISION_FILE_PATH.string(), + provision.set(ZoneProvisioningConfig::Link({SOME_FILE_PATH.string(), linkFile.string()})); - config.units.push_back(unit); - config::saveToJsonFile(PROVISION_FILE_PATH.string(), config); + config.provisions.push_back(provision); + save(config); { - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.start(); BOOST_CHECK(!fs::exists(ROOTFS_PATH / linkFile)); @@ -202,7 +225,7 @@ BOOST_AUTO_TEST_CASE(LinkTest) zoneProvision.stop(); } { - ZoneProvision zoneProvision(ZONE_PATH.string(), {"/tmp/"}); + ZoneProvision zoneProvision = create({"/tmp/"}); zoneProvision.start(); BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile)); @@ -213,82 +236,81 @@ BOOST_AUTO_TEST_CASE(LinkTest) BOOST_AUTO_TEST_CASE(DeclareFileTest) { - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.declareFile(1, "path", 0747, 0777); zoneProvision.declareFile(2, "path", 0747, 0777); - ZoneProvisioning config; - BOOST_REQUIRE_NO_THROW(loadFromJsonFile(PROVISION_FILE_PATH.string(), config)); - BOOST_REQUIRE_EQUAL(config.units.size(), 2); - BOOST_REQUIRE(config.units[0].is()); - BOOST_REQUIRE(config.units[1].is()); - const ZoneProvisioning::File& unit = config.units[0].as(); - BOOST_CHECK_EQUAL(unit.type, 1); - BOOST_CHECK_EQUAL(unit.path, "path"); - BOOST_CHECK_EQUAL(unit.flags, 0747); - BOOST_CHECK_EQUAL(unit.mode, 0777); + ZoneProvisioningConfig config; + load(config); + BOOST_REQUIRE_EQUAL(config.provisions.size(), 2); + BOOST_REQUIRE(config.provisions[0].is()); + BOOST_REQUIRE(config.provisions[1].is()); + const ZoneProvisioningConfig::File& provision = config.provisions[0].as(); + BOOST_CHECK_EQUAL(provision.type, 1); + BOOST_CHECK_EQUAL(provision.path, "path"); + BOOST_CHECK_EQUAL(provision.flags, 0747); + BOOST_CHECK_EQUAL(provision.mode, 0777); } BOOST_AUTO_TEST_CASE(DeclareMountTest) { - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake"); zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"); - ZoneProvisioning config; - BOOST_REQUIRE_NO_THROW(loadFromJsonFile(PROVISION_FILE_PATH.string(), config)); - BOOST_REQUIRE_EQUAL(config.units.size(), 2); - BOOST_REQUIRE(config.units[0].is()); - BOOST_REQUIRE(config.units[1].is()); - const ZoneProvisioning::Mount& unit = config.units[0].as(); - BOOST_CHECK_EQUAL(unit.source, "/fake/path1"); - BOOST_CHECK_EQUAL(unit.target, "/fake/path2"); - BOOST_CHECK_EQUAL(unit.type, "tmpfs"); - BOOST_CHECK_EQUAL(unit.flags, 077); - BOOST_CHECK_EQUAL(unit.data, "fake"); + ZoneProvisioningConfig config; + load(config); + BOOST_REQUIRE_EQUAL(config.provisions.size(), 2); + BOOST_REQUIRE(config.provisions[0].is()); + BOOST_REQUIRE(config.provisions[1].is()); + const ZoneProvisioningConfig::Mount& provision = config.provisions[0].as(); + BOOST_CHECK_EQUAL(provision.source, "/fake/path1"); + BOOST_CHECK_EQUAL(provision.target, "/fake/path2"); + BOOST_CHECK_EQUAL(provision.type, "tmpfs"); + BOOST_CHECK_EQUAL(provision.flags, 077); + BOOST_CHECK_EQUAL(provision.data, "fake"); } BOOST_AUTO_TEST_CASE(DeclareLinkTest) { - ZoneProvision zoneProvision(ZONE_PATH.string(), {}); + ZoneProvision zoneProvision = create({}); zoneProvision.declareLink("/fake/path1", "/fake/path2"); zoneProvision.declareLink("/fake/path2", "/fake/path2"); - ZoneProvisioning config; - BOOST_REQUIRE_NO_THROW(loadFromJsonFile(PROVISION_FILE_PATH.string(), config)); - BOOST_REQUIRE_EQUAL(config.units.size(), 2); - BOOST_REQUIRE(config.units[0].is()); - BOOST_REQUIRE(config.units[1].is()); - const ZoneProvisioning::Link& unit = config.units[0].as(); - BOOST_CHECK_EQUAL(unit.source, "/fake/path1"); - BOOST_CHECK_EQUAL(unit.target, "/fake/path2"); + ZoneProvisioningConfig config; + load(config); + BOOST_REQUIRE_EQUAL(config.provisions.size(), 2); + BOOST_REQUIRE(config.provisions[0].is()); + BOOST_REQUIRE(config.provisions[1].is()); + const ZoneProvisioningConfig::Link& provision = config.provisions[0].as(); + BOOST_CHECK_EQUAL(provision.source, "/fake/path1"); + BOOST_CHECK_EQUAL(provision.target, "/fake/path2"); } BOOST_AUTO_TEST_CASE(ProvisionedAlreadyTest) { - const fs::path dir = fs::path("/opt/usr/data/ut-from-host-provision"); - const fs::path linkFile = fs::path("/ut-from-host-provision.conf"); + const fs::path dir = fs::path("/opt/usr/data/ut-from-host"); + const fs::path linkFile = fs::path("/ut-from-host-file.txt"); const fs::path regularFile = fs::path("/opt/usr/data/ut-regular-file"); - ZoneProvisioning config; - ZoneProvisioning::Unit unit; - unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY, + ZoneProvisioningConfig config; + ZoneProvisioningConfig::Provision provision; + provision.set(ZoneProvisioningConfig::File({VSMFILE_DIRECTORY, dir.string(), 0, 0777})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::Link({PROVISION_FILE_PATH.string(), + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::Link({SOME_FILE_PATH.string(), linkFile.string()})); - config.units.push_back(unit); - unit.set(ZoneProvisioning::File({VSMFILE_REGULAR, + config.provisions.push_back(provision); + provision.set(ZoneProvisioningConfig::File({VSMFILE_REGULAR, regularFile.string(), O_CREAT, 0777})); - config.units.push_back(unit); - - config::saveToJsonFile(PROVISION_FILE_PATH.string(), config); + config.provisions.push_back(provision); + save(config); - ZoneProvision zoneProvision(ZONE_PATH.string(), {"/tmp/"}); + ZoneProvision zoneProvision = create({"/tmp/"}); zoneProvision.start(); BOOST_CHECK(fs::exists(ROOTFS_PATH / dir)); diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index 80e73da..783fbf8 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -51,6 +51,7 @@ const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zo const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/config.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR; +const std::string DB_PATH = ZONES_PATH + "/vasum.db"; struct Fixture { utils::ScopedGlibLoop mLoop; @@ -66,6 +67,7 @@ struct Fixture { return std::unique_ptr(new Zone(utils::Worker::create(), ZONES_PATH, configPath, + DB_PATH, LXC_TEMPLATES_PATH, "")); } -- 2.7.4 From ca9d04423d356228266a2480231e77b624cf5876 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Tue, 20 Jan 2015 16:15:39 +0100 Subject: [PATCH 04/16] IPC: Support older glib [Bug/Feature] Replaced new calls with older equivalents Fixed SIGSEGV bug [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: I572321fb4055f8f5b033b755c883c3e4b00bfcda --- common/ipc/client.cpp | 62 ++++++++++-- common/ipc/client.hpp | 31 +++--- common/ipc/internals/add-peer-request.hpp | 2 +- common/ipc/internals/finish-request.hpp | 2 +- common/ipc/internals/method-request.hpp | 2 +- common/ipc/internals/processor.cpp | 12 +-- common/ipc/internals/processor.hpp | 17 ++-- common/ipc/internals/remove-peer-request.hpp | 2 +- common/ipc/internals/request-queue.hpp | 2 +- common/ipc/internals/signal-request.hpp | 2 +- common/ipc/ipc-gsource.cpp | 141 ++++++++++++++------------ common/ipc/ipc-gsource.hpp | 58 +++++------ common/ipc/service.cpp | 109 +++++++++++++------- common/ipc/service.hpp | 31 +++--- common/ipc/types.cpp | 2 +- common/ipc/types.hpp | 2 +- tests/unit_tests/ipc/ut-ipc.cpp | 142 ++++++++------------------- 17 files changed, 327 insertions(+), 292 deletions(-) diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp index 16f77e6..1b7ae56 100644 --- a/common/ipc/client.cpp +++ b/common/ipc/client.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -36,6 +36,8 @@ Client::Client(const std::string& socketPath) mSocketPath(socketPath) { LOGS("Client Constructor"); + setNewPeerCallback(nullptr); + setRemovedPeerCallback(nullptr); } Client::~Client() @@ -52,10 +54,14 @@ void Client::start(const bool usesExternalPolling) { LOGS("Client start"); // Initialize the connection with the server + if (usesExternalPolling) { + startPoll(); + } + mProcessor.start(usesExternalPolling); + LOGD("Connecting to " + mSocketPath); auto socketPtr = std::make_shared(Socket::connectSocket(mSocketPath)); mServiceFD = mProcessor.addPeer(socketPtr); - mProcessor.start(usesExternalPolling); } bool Client::isStarted() @@ -65,21 +71,41 @@ bool Client::isStarted() void Client::stop() { - LOGS("Client Destructor"); + LOGS("Client stop"); mProcessor.stop(); + + if (mIPCGSourcePtr) { + stopPoll(); + } } -std::vector Client::getFDs() +void Client::startPoll() { - std::vector fds; - fds.push_back(mProcessor.getEventFD()); - fds.push_back(mServiceFD); + LOGS("Client startPoll"); + using namespace std::placeholders; + mIPCGSourcePtr = IPCGSource::create(std::bind(&Client::handle, this, _1, _2)); + mIPCGSourcePtr->addFD(mProcessor.getEventFD()); + mIPCGSourcePtr->attach(); +} + +void Client::stopPoll() +{ + LOGS("Client stopPoll"); - return fds; + mIPCGSourcePtr->removeFD(mProcessor.getEventFD()); + mIPCGSourcePtr->detach(); + mIPCGSourcePtr.reset(); } void Client::handle(const FileDescriptor fd, const short pollEvent) { + LOGS("Client handle"); + + if (!isStarted()) { + LOGW("Client stopped"); + return; + } + if (fd == mProcessor.getEventFD() && (pollEvent & POLLIN)) { mProcessor.handleEvent(); return; @@ -97,13 +123,29 @@ void Client::handle(const FileDescriptor fd, const short pollEvent) void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Client setNewPeerCallback"); - mProcessor.setNewPeerCallback(newPeerCallback); + auto callback = [newPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->addFD(fd); + } + if (newPeerCallback) { + newPeerCallback(fd); + } + }; + mProcessor.setNewPeerCallback(callback); } void Client::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Client setRemovedPeerCallback"); - mProcessor.setRemovedPeerCallback(removedPeerCallback); + auto callback = [removedPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->removeFD(fd); + } + if (removedPeerCallback) { + removedPeerCallback(fd); + } + }; + mProcessor.setRemovedPeerCallback(callback); } void Client::removeMethod(const MethodID methodID) diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index 7b86198..eedf81b 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,6 +26,7 @@ #define COMMON_IPC_CLIENT_HPP #include "ipc/internals/processor.hpp" +#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "logger/logger.hpp" @@ -72,13 +73,6 @@ public: void stop(); /** - * Used with an external polling loop - * - * @return vector of internal file descriptors - */ - std::vector getFDs(); - - /** * Used with an external polling loop. * Handles one event from the file descriptor. * @@ -111,7 +105,7 @@ public: * @param method method handling implementation */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** @@ -124,7 +118,7 @@ public: * @tparam ReceivedDataType data type to serialize */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& signal); /** @@ -175,25 +169,30 @@ public: const std::shared_ptr& data); private: + + void startPoll(); + void stopPoll(); + FileDescriptor mServiceFD; Processor mProcessor; std::string mSocketPath; + IPCGSource::Pointer mIPCGSourcePtr; }; template -void Client::addMethodHandler(const MethodID methodID, +void Client::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { - LOGS("Client addMethodHandler, methodID: " << methodID); - mProcessor.addMethodHandler(methodID, method); + LOGS("Client setMethodHandler, methodID: " << methodID); + mProcessor.setMethodHandler(methodID, method); } template -void Client::addSignalHandler(const MethodID methodID, +void Client::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { - LOGS("Client addSignalHandler, methodID: " << methodID); - mProcessor.addSignalHandler(methodID, handler); + LOGS("Client setSignalHandler, methodID: " << methodID); + mProcessor.setSignalHandler(methodID, handler); } template diff --git a/common/ipc/internals/add-peer-request.hpp b/common/ipc/internals/add-peer-request.hpp index 05c5524..3409ba5 100644 --- a/common/ipc/internals/add-peer-request.hpp +++ b/common/ipc/internals/add-peer-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/finish-request.hpp b/common/ipc/internals/finish-request.hpp index 3019475..3fd4a4f 100644 --- a/common/ipc/internals/finish-request.hpp +++ b/common/ipc/internals/finish-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/method-request.hpp b/common/ipc/internals/method-request.hpp index f9860f7..36d3d7a 100644 --- a/common/ipc/internals/method-request.hpp +++ b/common/ipc/internals/method-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 05c97aa..bdc8a8d 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -66,7 +66,7 @@ Processor::Processor(const std::string& logName, utils::signalBlock(SIGPIPE); using namespace std::placeholders; - addMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID, + setMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID, std::bind(&Processor::onNewSignals, this, _1, _2)); } @@ -94,6 +94,7 @@ void Processor::start(bool usesExternalPolling) if (!isStarted()) { LOGI(mLogPrefix + "Processor start"); mIsRunning = true; + mUsesExternalPolling = usesExternalPolling; if (!usesExternalPolling) { mThread = std::thread(&Processor::run, this); } @@ -228,7 +229,6 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, Status status) mRemovedPeerCallback(peerFD); } - resetPolling(); } @@ -236,8 +236,7 @@ void Processor::resetPolling() { LOGS(mLogPrefix + "Processor resetPolling"); - if (!isStarted()) { - LOGW(mLogPrefix + "Processor not started! Polling not reset!"); + if (mUsesExternalPolling) { return; } @@ -681,7 +680,7 @@ bool Processor::onFinishRequest(FinishRequest& request) break; } case Event::REMOVE_PEER: { - request.get()->conditionPtr->notify_all(); + onRemovePeerRequest(*request.get()); break; } case Event::SIGNAL: @@ -692,6 +691,7 @@ bool Processor::onFinishRequest(FinishRequest& request) } mIsRunning = false; + request.conditionPtr->notify_all(); return true; } diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index 157f39c..40dd4c0 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -190,7 +190,7 @@ public: * @tparam ReceivedDataType data type to receive */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& process); /** @@ -208,7 +208,7 @@ public: * @tparam ReceivedDataType data type to receive */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& process); /** @@ -360,6 +360,7 @@ private: RequestQueue mRequestQueue; bool mIsRunning; + bool mUsesExternalPolling; std::unordered_map> mMethodsCallbacks; std::unordered_map> mSignalsCallbacks; @@ -381,7 +382,7 @@ private: std::thread mThread; template - void addMethodHandlerInternal(const MethodID methodID, + void setMethodHandlerInternal(const MethodID methodID, const typename MethodHandler::type& process); template @@ -420,7 +421,7 @@ private: }; template -void Processor::addMethodHandlerInternal(const MethodID methodID, +void Processor::setMethodHandlerInternal(const MethodID methodID, const typename MethodHandler::type& method) { MethodHandlers methodCall; @@ -447,7 +448,7 @@ void Processor::addMethodHandlerInternal(const MethodID methodID, } template -void Processor::addMethodHandler(const MethodID methodID, +void Processor::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { if (methodID == RETURN_METHOD_ID || methodID == REGISTER_SIGNAL_METHOD_ID) { @@ -463,13 +464,13 @@ void Processor::addMethodHandler(const MethodID methodID, throw IPCException("MethodID used by a signal: " + std::to_string(methodID)); } - addMethodHandlerInternal(methodID, method); + setMethodHandlerInternal(methodID, method); } } template -void Processor::addSignalHandler(const MethodID methodID, +void Processor::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { if (methodID == RETURN_METHOD_ID || methodID == REGISTER_SIGNAL_METHOD_ID) { diff --git a/common/ipc/internals/remove-peer-request.hpp b/common/ipc/internals/remove-peer-request.hpp index ec01ac4..4ec07cb 100644 --- a/common/ipc/internals/remove-peer-request.hpp +++ b/common/ipc/internals/remove-peer-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/request-queue.hpp b/common/ipc/internals/request-queue.hpp index 35b5120..82ba606 100644 --- a/common/ipc/internals/request-queue.hpp +++ b/common/ipc/internals/request-queue.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/signal-request.hpp b/common/ipc/internals/signal-request.hpp index 4cf62c2..ad80d91 100644 --- a/common/ipc/internals/signal-request.hpp +++ b/common/ipc/internals/signal-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/ipc-gsource.cpp b/common/ipc/ipc-gsource.cpp index 5a4e137..1769414 100644 --- a/common/ipc/ipc-gsource.cpp +++ b/common/ipc/ipc-gsource.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,10 +26,9 @@ #include "config.hpp" #include "ipc/ipc-gsource.hpp" - -#if GLIB_CHECK_VERSION(2,36,0) - +#include "utils/callback-wrapper.hpp" #include "logger/logger.hpp" + #include namespace vasum { @@ -37,33 +36,26 @@ namespace ipc { namespace { +gushort conditions = static_cast(G_IO_IN | + G_IO_ERR | + G_IO_HUP); -GIOCondition conditions = static_cast(G_IO_IN | - G_IO_ERR | - G_IO_HUP); } - -IPCGSource::IPCGSource(const std::vector fds, - const HandlerCallback& handlerCallback) +IPCGSource::IPCGSource(const HandlerCallback& handlerCallback) : mHandlerCallback(handlerCallback) { - LOGS("IPCGSource constructor"); - - for (const FileDescriptor fd : fds) { - addFD(fd); - } + LOGT("IPCGSource Constructor"); } IPCGSource::~IPCGSource() { - LOGS("~IPCGSource"); + LOGT("IPCGSource Destructor"); } -IPCGSource::Pointer IPCGSource::create(const std::vector& fds, - const HandlerCallback& handlerCallback) +IPCGSource::Pointer IPCGSource::create(const HandlerCallback& handlerCallback) { - LOGS("Creating IPCGSource"); + LOGT("Creating IPCGSource"); static GSourceFuncs funcs = { &IPCGSource::prepare, &IPCGSource::check, @@ -79,64 +71,96 @@ IPCGSource::Pointer IPCGSource::create(const std::vector& fds, // Fill additional data IPCGSource* source = reinterpret_cast(gSource); - new(source)IPCGSource(fds, handlerCallback); + new(source) IPCGSource(handlerCallback); auto deleter = [](IPCGSource * ptr) { LOGD("Deleter"); - - if (!g_source_is_destroyed(&(ptr->mGSource))) { - // This way finalize method will be run in glib loop's thread - g_source_destroy(&(ptr->mGSource)); - } + g_source_unref(&ptr->mGSource); }; - return std::shared_ptr(source, deleter); + Pointer ipcGSourcePtr(source, deleter); + + g_source_set_callback(gSource, + &IPCGSource::onHandlerCall, + utils::createCallbackWrapper(Pointer(ipcGSourcePtr), ipcGSourcePtr->mGuard.spawn()), + &utils::deleteCallbackWrapper); + + return ipcGSourcePtr; } void IPCGSource::addFD(const FileDescriptor fd) { + LOGI("Adding to glib FD: " << fd); + Lock lock(mStateMutex); - if (!&mGSource) { - // In case it's called as a callback but the IPCGSource is destroyed - return; - } - LOGS("Adding fd to glib"); - - gpointer tag = g_source_add_unix_fd(&mGSource, - fd, - conditions); - FDInfo fdInfo(tag, fd); - mFDInfos.push_back(std::move(fdInfo)); + mGPollFDs.push_back({fd, conditions, 0}); + g_source_add_poll(&mGSource, &mGPollFDs.back()); } void IPCGSource::removeFD(const FileDescriptor fd) { - if (!&mGSource) { - // In case it's called as a callback but the IPCGSource is destroyed - return; - } + Lock lock(mStateMutex); + + auto it = std::find_if(mGPollFDs.begin(), mGPollFDs.end(), [fd](GPollFD gPollFD) { + return gPollFD.fd = fd; + }); - LOGS("Removing fd from glib"); - auto it = std::find(mFDInfos.begin(), mFDInfos.end(), fd); - if (it == mFDInfos.end()) { + if (it == mGPollFDs.end()) { LOGE("No such fd"); return; } - g_source_remove_unix_fd(&mGSource, it->tag); - mFDInfos.erase(it); + g_source_remove_poll(&mGSource, &(*it)); + mGPollFDs.erase(it); + LOGI("Removed from glib FD: " << fd); } guint IPCGSource::attach(GMainContext* context) { - LOGS("Attaching to GMainContext"); + LOGT("Attaching to GMainContext"); guint ret = g_source_attach(&mGSource, context); - g_source_unref(&mGSource); return ret; } +void IPCGSource::detach() +{ + LOGT("Detaching"); + Lock lock(mStateMutex); + + for (GPollFD gPollFD : mGPollFDs) { + g_source_remove_poll(&mGSource, &gPollFD); + } + + mGPollFDs.clear(); + if (!g_source_is_destroyed(&mGSource)) { + LOGD("Destroying"); + // This way finalize method will be run in glib loop's thread + g_source_destroy(&mGSource); + } +} + +void IPCGSource::callHandler() +{ + Lock lock(mStateMutex); + + for (const GPollFD& gPollFD : mGPollFDs) { + if (gPollFD.revents & conditions) { + mHandlerCallback(gPollFD.fd, gPollFD.revents); + } + } +} + +gboolean IPCGSource::onHandlerCall(gpointer userData) +{ + const auto& source = utils::getCallbackFromPointer(userData); + if (source) { + source->callHandler(); + } + return TRUE; +} + gboolean IPCGSource::prepare(GSource* gSource, gint* timeout) { - if (!gSource) { + if (!gSource || g_source_is_destroyed(gSource)) { return FALSE; } @@ -149,7 +173,7 @@ gboolean IPCGSource::prepare(GSource* gSource, gint* timeout) gboolean IPCGSource::check(GSource* gSource) { - if (!gSource) { + if (!gSource || g_source_is_destroyed(gSource)) { return FALSE; } @@ -157,21 +181,16 @@ gboolean IPCGSource::check(GSource* gSource) } gboolean IPCGSource::dispatch(GSource* gSource, - GSourceFunc /*callback*/, - gpointer /*userData*/) + GSourceFunc callback, + gpointer userData) { if (!gSource || g_source_is_destroyed(gSource)) { // Remove the GSource from the GMainContext return FALSE; } - IPCGSource* source = reinterpret_cast(gSource); - - for (const FDInfo fdInfo : source->mFDInfos) { - GIOCondition cond = g_source_query_unix_fd(gSource, fdInfo.tag); - if (conditions & cond) { - source->mHandlerCallback(fdInfo.fd, cond); - } + if (callback) { + callback(userData); } return TRUE; @@ -179,8 +198,6 @@ gboolean IPCGSource::dispatch(GSource* gSource, void IPCGSource::finalize(GSource* gSource) { - LOGS("IPCGSource Finalize"); - if (gSource) { IPCGSource* source = reinterpret_cast(gSource); source->~IPCGSource(); @@ -189,5 +206,3 @@ void IPCGSource::finalize(GSource* gSource) } // namespace ipc } // namespace vasum - -#endif // GLIB_CHECK_VERSION diff --git a/common/ipc/ipc-gsource.hpp b/common/ipc/ipc-gsource.hpp index bb9a096..87057db 100644 --- a/common/ipc/ipc-gsource.hpp +++ b/common/ipc/ipc-gsource.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,12 +26,12 @@ #define COMMON_IPC_IPC_GSOURCE_HPP #include -#if GLIB_CHECK_VERSION(2,36,0) - -#include "ipc/service.hpp" #include "ipc/types.hpp" +#include "utils/callback-guard.hpp" #include +#include +#include namespace vasum { @@ -82,18 +82,32 @@ public: guint attach(GMainContext* context = nullptr); /** + * After this method quits handlerCallback will not be called + */ + void detach(); + + /** * Creates the IPCGSource class in the memory allocated by glib. * Calls IPCGSource's constructor * - * @param fds initial set of file descriptors * @param handlerCallback event handling callback * * @return pointer to the IPCGSource */ - static Pointer create(const std::vector& fds, - const HandlerCallback& handlerCallback); + static Pointer create(const HandlerCallback& handlerCallback); + + /** + * Callback for the dispatch function + */ + static gboolean onHandlerCall(gpointer userData); + + /** + * Locks the internal state mutex and calls the handler callback for each fd + */ + void callHandler(); private: + typedef std::unique_lock Lock; /** * GSourceFuncs' callback @@ -117,38 +131,18 @@ private: */ static void finalize(GSource* source); - - // Called only from IPCGSource::create - IPCGSource(const std::vector fds, - const HandlerCallback& handlerCallback); - - struct FDInfo { - FDInfo(gpointer tag, FileDescriptor fd) - : tag(tag), fd(fd) {} - - bool operator==(const gpointer t) - { - return t == tag; - } - - bool operator==(const FileDescriptor f) - { - return f == fd; - } - - gpointer tag; - FileDescriptor fd; - }; + IPCGSource(const HandlerCallback& handlerCallback); GSource mGSource; HandlerCallback mHandlerCallback; - std::vector mFDInfos; + std::list mGPollFDs; + utils::CallbackGuard mGuard; + std::recursive_mutex mStateMutex; + }; } // namespace ipc } // namespace vasum -#endif // GLIB_CHECK_VERSION - #endif // COMMON_IPC_IPC_GSOURCE_HPP diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index b96bcd4..9bf721b 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -1,26 +1,26 @@ -// /* -// * 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 -// */ +/* +* Copyright (c) 2015 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" @@ -36,11 +36,13 @@ namespace ipc { Service::Service(const std::string& socketPath, const PeerCallback& addPeerCallback, const PeerCallback& removePeerCallback) - : mProcessor("[SERVICE] ", addPeerCallback, removePeerCallback), + : mProcessor("[SERVICE] "), mAcceptor(socketPath, std::bind(&Processor::addPeer, &mProcessor, _1)) { LOGS("Service Constructor"); + setNewPeerCallback(addPeerCallback); + setRemovedPeerCallback(removePeerCallback); } Service::~Service() @@ -56,6 +58,9 @@ Service::~Service() void Service::start(const bool usesExternalPolling) { LOGS("Service start"); + if (usesExternalPolling) { + startPoll(); + } mProcessor.start(usesExternalPolling); // There can be an incoming connection from mAcceptor before mProcessor is listening, @@ -75,20 +80,43 @@ void Service::stop() LOGS("Service stop"); mAcceptor.stop(); mProcessor.stop(); + + if (mIPCGSourcePtr) { + stopPoll(); + } +} + +void Service::startPoll() +{ + LOGS("Service startPoll"); + + mIPCGSourcePtr = IPCGSource::create(std::bind(&Service::handle, this, _1, _2)); + mIPCGSourcePtr->addFD(mAcceptor.getEventFD()); + mIPCGSourcePtr->addFD(mAcceptor.getConnectionFD()); + mIPCGSourcePtr->addFD(mProcessor.getEventFD()); + mIPCGSourcePtr->attach(); } -std::vector Service::getFDs() +void Service::stopPoll() { - std::vector fds; - fds.push_back(mAcceptor.getEventFD()); - fds.push_back(mAcceptor.getConnectionFD()); - fds.push_back(mProcessor.getEventFD()); + LOGS("Service stopPoll"); - return fds; + mIPCGSourcePtr->removeFD(mAcceptor.getEventFD()); + mIPCGSourcePtr->removeFD(mAcceptor.getConnectionFD()); + mIPCGSourcePtr->removeFD(mProcessor.getEventFD()); + mIPCGSourcePtr->detach(); + mIPCGSourcePtr.reset(); } void Service::handle(const FileDescriptor fd, const short pollEvent) { + LOGS("Service handle"); + + if (!isStarted()) { + LOGW("Service stopped"); + return; + } + if (fd == mProcessor.getEventFD() && (pollEvent & POLLIN)) { mProcessor.handleEvent(); return; @@ -111,17 +139,32 @@ void Service::handle(const FileDescriptor fd, const short pollEvent) } } - void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Service setNewPeerCallback"); - mProcessor.setNewPeerCallback(newPeerCallback); + auto callback = [newPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->addFD(fd); + } + if (newPeerCallback) { + newPeerCallback(fd); + } + }; + mProcessor.setNewPeerCallback(callback); } void Service::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Service setRemovedPeerCallback"); - mProcessor.setRemovedPeerCallback(removedPeerCallback); + auto callback = [removedPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->removeFD(fd); + } + if (removedPeerCallback) { + removedPeerCallback(fd); + } + }; + mProcessor.setRemovedPeerCallback(callback); } void Service::removeMethod(const MethodID methodID) diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 9392a42..34b73fd 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -27,6 +27,7 @@ #include "ipc/internals/processor.hpp" #include "ipc/internals/acceptor.hpp" +#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "logger/logger.hpp" @@ -77,13 +78,6 @@ public: void stop(); /** - * Used with an external polling loop - * - * @return vector of internal file descriptors - */ - std::vector getFDs(); - - /** * Used with an external polling loop. * Handles one event from the file descriptor. * @@ -116,7 +110,7 @@ public: * @param method method handling implementation */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** @@ -129,7 +123,7 @@ public: * @tparam ReceivedDataType data type to serialize */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler); /** @@ -180,26 +174,31 @@ public: void signal(const MethodID methodID, const std::shared_ptr& data); private: + + void startPoll(); + void stopPoll(); + typedef std::lock_guard Lock; Processor mProcessor; Acceptor mAcceptor; + IPCGSource::Pointer mIPCGSourcePtr; }; template -void Service::addMethodHandler(const MethodID methodID, +void Service::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { - LOGS("Service addMethodHandler, methodID " << methodID); - mProcessor.addMethodHandler(methodID, method); + LOGS("Service setMethodHandler, methodID " << methodID); + mProcessor.setMethodHandler(methodID, method); } template -void Service::addSignalHandler(const MethodID methodID, +void Service::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { - LOGS("Service addSignalHandler, methodID " << methodID); - mProcessor.addSignalHandler(methodID, handler); + LOGS("Service setSignalHandler, methodID " << methodID); + mProcessor.setSignalHandler(methodID, handler); } template diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp index ba4c1c4..5d7dab6 100644 --- a/common/ipc/types.cpp +++ b/common/ipc/types.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index 10b87df..6186f65 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index c14b2a0..a15027c 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -33,7 +33,6 @@ #include "ipc/service.hpp" #include "ipc/client.hpp" -#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "utils/glib-loop.hpp" #include "utils/latch.hpp" @@ -148,7 +147,7 @@ std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr return data; } -FileDescriptor connect(Service& s, Client& c) +FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) { // Connects the Client to the Service and returns Clients FileDescriptor ValueLatch peerFDLatch; @@ -159,10 +158,10 @@ FileDescriptor connect(Service& s, Client& c) s.setNewPeerCallback(newPeerCallback); if (!s.isStarted()) { - s.start(); + s.start(isServiceGlib); } - c.start(); + c.start(isClientGlib); FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); s.setNewPeerCallback(nullptr); @@ -170,66 +169,16 @@ FileDescriptor connect(Service& s, Client& c) return peerFD; } -#if GLIB_CHECK_VERSION(2,36,0) - -std::pair connectServiceGSource(Service& s, Client& c) +FileDescriptor connectServiceGSource(Service& s, Client& c) { - ValueLatch peerFDLatch; - IPCGSource::Pointer ipcGSourcePtr = IPCGSource::create(s.getFDs(), std::bind(&Service::handle, &s, _1, _2)); - - auto newPeerCallback = [&peerFDLatch, ipcGSourcePtr](const FileDescriptor newFD) { - if (ipcGSourcePtr) { - //TODO: Remove this if - ipcGSourcePtr->addFD(newFD); - } - peerFDLatch.set(newFD); - }; - - - s.setNewPeerCallback(newPeerCallback); - s.setRemovedPeerCallback(std::bind(&IPCGSource::removeFD, ipcGSourcePtr, _1)); - s.start(true); - // Service starts to process - ipcGSourcePtr->attach(); - - c.start(); - - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); - s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return std::make_pair(peerFD, ipcGSourcePtr); + return connect(s, c, true, false); } -std::pair connectClientGSource(Service& s, Client& c) +FileDescriptor connectClientGSource(Service& s, Client& c) { - // Connects the Client to the Service and returns Clients FileDescriptor - ValueLatch peerFDLatch; - auto newPeerCallback = [&peerFDLatch](const FileDescriptor newFD) { - peerFDLatch.set(newFD); - }; - s.setNewPeerCallback(newPeerCallback); - - if (!s.isStarted()) { - // Service starts to process - s.start(); - } - - - c.start(true); - IPCGSource::Pointer ipcGSourcePtr = IPCGSource::create(c.getFDs(), - std::bind(&Client::handle, &c, _1, _2)); - - ipcGSourcePtr->attach(); - - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); - s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return std::make_pair(peerFD, ipcGSourcePtr); + return connect(s, c, false, true); } -#endif // GLIB_CHECK_VERSION - - void testEcho(Client& c, const MethodID methodID) { std::shared_ptr sentData(new SendData(34)); @@ -260,13 +209,13 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructor) BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) { Service s(socketPath); - s.addMethodHandler(1, returnEmptyCallback); - s.addMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnEmptyCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); - s.addMethodHandler(1, echoCallback); - s.addMethodHandler(2, returnDataCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, returnDataCallback); Client c(socketPath); connect(s, c); @@ -282,13 +231,13 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, returnEmptyCallback); - c.addMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnEmptyCallback); + c.setMethodHandler(1, returnDataCallback); FileDescriptor peerFD = connect(s, c); - c.addMethodHandler(1, echoCallback); - c.addMethodHandler(2, returnDataCallback); + c.setMethodHandler(1, echoCallback); + c.setMethodHandler(2, returnDataCallback); testEcho(s, 1, peerFD); @@ -302,7 +251,7 @@ BOOST_AUTO_TEST_CASE(ServiceStartStop) { Service s(socketPath); - s.addMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); s.stop(); @@ -317,7 +266,7 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnDataCallback); c.start(); c.stop(); @@ -334,8 +283,8 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); - s.addMethodHandler(2, echoCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); connect(s, c); @@ -347,9 +296,9 @@ BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) BOOST_AUTO_TEST_CASE(Restart) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); - s.addMethodHandler(2, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); c.start(); @@ -373,7 +322,7 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); std::shared_ptr sentData(new SendData(56)); @@ -389,7 +338,7 @@ BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho) // Setup Service and Client Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); c.start(); @@ -414,7 +363,7 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); // Async call @@ -435,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) BOOST_AUTO_TEST_CASE(SyncTimeout) { Service s(socketPath); - s.addMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); @@ -447,7 +396,7 @@ BOOST_AUTO_TEST_CASE(SyncTimeout) BOOST_AUTO_TEST_CASE(SerializationError) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); connect(s, c); @@ -461,7 +410,7 @@ BOOST_AUTO_TEST_CASE(SerializationError) BOOST_AUTO_TEST_CASE(ParseError) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -481,7 +430,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) }; // Method will throw during serialization and disconnect automatically - s.addMethodHandler(1, method); + s.setMethodHandler(1, method); s.start(); Client c(socketPath); @@ -510,7 +459,7 @@ BOOST_AUTO_TEST_CASE(ReadTimeout) auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); }; - s.addMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); @@ -524,7 +473,7 @@ BOOST_AUTO_TEST_CASE(ReadTimeout) BOOST_AUTO_TEST_CASE(WriteTimeout) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -559,8 +508,8 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) latchB.set(); }; - c.addSignalHandler(1, handlerA); - c.addSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); // Wait for the signals to propagate to the Service std::this_thread::sleep_for(std::chrono::milliseconds(2 * TIMEOUT)); @@ -590,8 +539,8 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) latchB.set(); }; - c.addSignalHandler(1, handlerA); - c.addSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); connect(s, c); @@ -606,9 +555,6 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) } -#if GLIB_CHECK_VERSION(2,36,0) - -// FIXME This test causes segfault, however it should work in GDB. BOOST_AUTO_TEST_CASE(ServiceGSource) { utils::Latch l; @@ -620,13 +566,12 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) IPCGSource::Pointer serviceGSource; Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); - s.addSignalHandler(2, signalHandler); + s.setSignalHandler(2, signalHandler); - auto ret = connectServiceGSource(s, c); - serviceGSource = ret.second; + connectServiceGSource(s, c); testEcho(c, 1); @@ -636,6 +581,7 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) BOOST_CHECK(l.wait(TIMEOUT)); } + BOOST_AUTO_TEST_CASE(ClientGSource) { utils::Latch l; @@ -650,12 +596,10 @@ BOOST_AUTO_TEST_CASE(ClientGSource) IPCGSource::Pointer clientGSource; Client c(socketPath); - c.addMethodHandler(1, echoCallback); - c.addSignalHandler(2, signalHandler); + c.setMethodHandler(1, echoCallback); + c.setSignalHandler(2, signalHandler); - auto ret = connectClientGSource(s, c); - FileDescriptor peerFD = ret.first; - clientGSource = ret.second; + FileDescriptor peerFD = connectClientGSource(s, c); testEcho(s, 1, peerFD); @@ -665,8 +609,6 @@ BOOST_AUTO_TEST_CASE(ClientGSource) BOOST_CHECK(l.wait(TIMEOUT)); } -#endif // GLIB_CHECK_VERSION - // BOOST_AUTO_TEST_CASE(ConnectionLimitTest) // { // unsigned oldLimit = ipc::getMaxFDNumber(); @@ -674,7 +616,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) // // Setup Service and many Clients // Service s(socketPath); -// s.addMethodHandler(1, echoCallback); +// s.setMethodHandler(1, echoCallback); // s.start(); // std::list clients; -- 2.7.4 From fee242388c9f5efbb54aa6c646d3709225be2b84 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Fri, 23 Jan 2015 16:32:02 +0100 Subject: [PATCH 05/16] Fix ut threading, ut refactor [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I9eca161ee3752f29611395dccc73e9ba8e614e6d --- common/ipc/internals/processor.hpp | 1 + tests/unit_tests/config/ut-kvstore.cpp | 38 ++++++- tests/unit_tests/dbus/ut-connection.cpp | 28 +++-- tests/unit_tests/ipc/ut-ipc.cpp | 182 ++++++++++++++++++-------------- 4 files changed, 152 insertions(+), 97 deletions(-) diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index 40dd4c0..c3bcc6b 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -548,6 +548,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, Status returnStatus = ipc::Status::UNDEFINED; auto process = [&result, &mutex, &cv, &returnStatus](Status status, std::shared_ptr returnedData) { + std::unique_lock lock(mutex); returnStatus = status; result = returnedData; cv.notify_all(); diff --git a/tests/unit_tests/config/ut-kvstore.cpp b/tests/unit_tests/config/ut-kvstore.cpp index 9855457..af2fa29 100644 --- a/tests/unit_tests/config/ut-kvstore.cpp +++ b/tests/unit_tests/config/ut-kvstore.cpp @@ -29,12 +29,15 @@ #include "config/kvstore.hpp" #include "config/exception.hpp" #include "utils/scoped-dir.hpp" +#include "utils/latch.hpp" #include #include +#include #include using namespace config; +using namespace vasum::utils; namespace fs = boost::filesystem; namespace { @@ -171,19 +174,19 @@ BOOST_AUTO_TEST_CASE(SingleValueTest) namespace { template -void setVector(Fixture& f, std::vector vec) +void setVector(Fixture& f, const std::vector& vec) { std::vector storedVec; BOOST_CHECK_NO_THROW(f.c.set(KEY, vec)); - BOOST_CHECK_NO_THROW(storedVec = f.c.get >(KEY)) + BOOST_CHECK_NO_THROW(storedVec = f.c.get>(KEY)) BOOST_CHECK_EQUAL_COLLECTIONS(storedVec.begin(), storedVec.end(), vec.begin(), vec.end()); } template void testVectorOfValues(Fixture& f, - std::vector a, - std::vector b, - std::vector c) + const std::vector& a, + const std::vector& b, + const std::vector& c) { // Set setVector(f, a); @@ -221,6 +224,31 @@ BOOST_AUTO_TEST_CASE(ClearTest) BOOST_CHECK_THROW(c.get(KEY), ConfigException); } +BOOST_AUTO_TEST_CASE(TransactionTest) +{ + auto t1 = c.getTransaction(); + BOOST_CHECK_EQUAL(t1.use_count(), 1); + + auto t2 = c.getTransaction(); + BOOST_CHECK_EQUAL(t1.use_count(), 2); + BOOST_CHECK_EQUAL(t2.use_count(), 2); +} + +BOOST_AUTO_TEST_CASE(TransactionTwoThreadsTest) +{ + Latch latch; + auto trans1 = c.getTransaction(); + std::thread thread([&]{ + auto trans2 = c.getTransaction(); + latch.set(); + }); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + BOOST_CHECK(latch.empty()); + trans1.reset(); + latch.wait(); + thread.join(); +} + BOOST_AUTO_TEST_CASE(KeyTest) { BOOST_CHECK_EQUAL(key(), ""); diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 96175ee..94b02b7 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -414,8 +414,9 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { - BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)); - callDone.set(); + if (g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)) { + callDone.set(); + } }; conn2->callMethodAsync(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, @@ -429,8 +430,9 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) auto asyncResult2 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { const gchar* ret = NULL; g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret); - BOOST_CHECK_EQUAL("resp: arg", ret); - callDone.set(); + if (ret == std::string("resp: arg")) { + callDone.set(); + } }; conn2->callMethodAsync(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, @@ -442,8 +444,12 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); auto asyncResult3 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { - BOOST_CHECK_THROW(asyncMethodCallResult.get(), DbusCustomException); - callDone.set(); + try { + asyncMethodCallResult.get(); + } catch (DbusCustomException&) { + //expected + callDone.set(); + } }; conn2->callMethodAsync(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, @@ -494,8 +500,9 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest) auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { const gchar* ret = NULL; g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret); - BOOST_CHECK_EQUAL("resp: arg", ret); - callDone.set(); + if (ret == std::string("resp: arg")) { + callDone.set(); + } }; conn2->callMethodAsync(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, @@ -583,8 +590,9 @@ BOOST_AUTO_TEST_CASE(DbusApiNotifyTest) DbusTestClient client; auto onNotify = [&](const std::string& message) { - BOOST_CHECK_EQUAL("notification", message); - notified.set(); + if (message == "notification") { + notified.set(); + } }; client.setNotifyCallback(onNotify); server.notifyClients("notification"); diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index a15027c..e5609f7 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -25,7 +25,6 @@ // TODO: Test connection limit // TODO: Refactor tests - function for setting up env -// TODO: Callback wrapper that waits till the callback is called #include "config.hpp" @@ -80,7 +79,17 @@ struct Fixture { struct SendData { int intVal; - SendData(int i = 0): intVal(i) {} + SendData(int i): intVal(i) {} + + CONFIG_REGISTER + ( + intVal + ) +}; + +struct RecvData { + int intVal; + RecvData(): intVal(-1) {} CONFIG_REGISTER ( @@ -128,23 +137,23 @@ struct ThrowOnAcceptData { std::shared_ptr returnEmptyCallback(const FileDescriptor, std::shared_ptr&) { - return std::shared_ptr(new EmptyData()); + return std::make_shared(); } -std::shared_ptr returnDataCallback(const FileDescriptor, std::shared_ptr&) +std::shared_ptr returnDataCallback(const FileDescriptor, std::shared_ptr&) { - return std::shared_ptr(new SendData(1)); + return std::make_shared(1); } -std::shared_ptr echoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr echoCallback(const FileDescriptor, std::shared_ptr& data) { - return data; + return std::make_shared(data->intVal); } -std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr& data) { std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME)); - return data; + return std::make_shared(data->intVal); } FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) @@ -182,7 +191,7 @@ FileDescriptor connectClientGSource(Service& s, Client& c) void testEcho(Client& c, const MethodID methodID) { std::shared_ptr sentData(new SendData(34)); - std::shared_ptr recvData = c.callSync(methodID, sentData, TIMEOUT); + std::shared_ptr recvData = c.callSync(methodID, sentData, TIMEOUT); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -190,7 +199,7 @@ void testEcho(Client& c, const MethodID methodID) void testEcho(Service& s, const MethodID methodID, const FileDescriptor peerFD) { std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(methodID, peerFD, sentData, TIMEOUT); + std::shared_ptr recvData = s.callSync(methodID, peerFD, sentData, TIMEOUT); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -210,12 +219,12 @@ BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) { Service s(socketPath); s.setMethodHandler(1, returnEmptyCallback); - s.setMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); - s.setMethodHandler(1, echoCallback); - s.setMethodHandler(2, returnDataCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, returnDataCallback); Client c(socketPath); connect(s, c); @@ -232,12 +241,12 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) Service s(socketPath); Client c(socketPath); c.setMethodHandler(1, returnEmptyCallback); - c.setMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnDataCallback); FileDescriptor peerFD = connect(s, c); - c.setMethodHandler(1, echoCallback); - c.setMethodHandler(2, returnDataCallback); + c.setMethodHandler(1, echoCallback); + c.setMethodHandler(2, returnDataCallback); testEcho(s, 1, peerFD); @@ -251,7 +260,7 @@ BOOST_AUTO_TEST_CASE(ServiceStartStop) { Service s(socketPath); - s.setMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); s.stop(); @@ -266,7 +275,7 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) { Service s(socketPath); Client c(socketPath); - c.setMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnDataCallback); c.start(); c.stop(); @@ -283,8 +292,8 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) { Service s(socketPath); - s.setMethodHandler(1, echoCallback); - s.setMethodHandler(2, echoCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); connect(s, c); @@ -296,9 +305,9 @@ BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) BOOST_AUTO_TEST_CASE(Restart) { Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); - s.setMethodHandler(2, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); c.start(); @@ -322,11 +331,11 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) { Service s(socketPath); Client c(socketPath); - c.setMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(1, peerFD, sentData); + std::shared_ptr recvData = s.callSync(1, peerFD, sentData); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -334,49 +343,49 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho) { std::shared_ptr sentData(new SendData(34)); - ValueLatch recvDataLatch; + ValueLatch> recvDataLatch; // Setup Service and Client Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); c.start(); //Async call - auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { + auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { if (status == ipc::Status::OK) { - recvDataLatch.set(*data); + recvDataLatch.set(data); } }; - c.callAsync(1, sentData, dataBack); + c.callAsync(1, sentData, dataBack); // Wait for the response - std::shared_ptr recvData(new SendData(recvDataLatch.get(TIMEOUT))); + std::shared_ptr recvData(recvDataLatch.get(TIMEOUT)); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) { std::shared_ptr sentData(new SendData(56)); - ValueLatch recvDataLatch; + ValueLatch> recvDataLatch; Service s(socketPath); Client c(socketPath); - c.setMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); // Async call - auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { + auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { if (status == ipc::Status::OK) { - recvDataLatch.set(*data); + recvDataLatch.set(data); } }; - s.callAsync(1, peerFD, sentData, dataBack); + s.callAsync(1, peerFD, sentData, dataBack); // Wait for the response - std::shared_ptr recvData(new SendData(recvDataLatch.get(TIMEOUT))); + std::shared_ptr recvData(recvDataLatch.get(TIMEOUT)); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -384,33 +393,33 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) BOOST_AUTO_TEST_CASE(SyncTimeout) { Service s(socketPath); - s.setMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); std::shared_ptr sentData(new SendData(78)); - BOOST_REQUIRE_THROW((c.callSync(1, sentData, TIMEOUT)), IPCException); + BOOST_REQUIRE_THROW((c.callSync(1, sentData, TIMEOUT)), IPCException); } BOOST_AUTO_TEST_CASE(SerializationError) { Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); connect(s, c); std::shared_ptr throwingData(new ThrowOnAcceptData()); - BOOST_CHECK_THROW((c.callSync(1, throwingData)), IPCSerializationException); + BOOST_CHECK_THROW((c.callSync(1, throwingData)), IPCSerializationException); } BOOST_AUTO_TEST_CASE(ParseError) { Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -436,12 +445,12 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) Client c(socketPath); c.start(); - auto dataBack = [&retStatusLatch](ipc::Status status, std::shared_ptr&) { + auto dataBack = [&retStatusLatch](ipc::Status status, std::shared_ptr&) { retStatusLatch.set(status); }; std::shared_ptr sentData(new SendData(78)); - c.callAsync(1, sentData, dataBack); + c.callAsync(1, sentData, dataBack); // Wait for the response ipc::Status retStatus = retStatusLatch.get(TIMEOUT); @@ -456,24 +465,24 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) BOOST_AUTO_TEST_CASE(ReadTimeout) { Service s(socketPath); - auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { + auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); }; - s.setMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); // Test timeout on read std::shared_ptr sentData(new SendData(334)); - BOOST_CHECK_THROW((c.callSync(1, sentData, TIMEOUT)), IPCException); + BOOST_CHECK_THROW((c.callSync(1, sentData, TIMEOUT)), IPCException); } BOOST_AUTO_TEST_CASE(WriteTimeout) { Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -481,77 +490,86 @@ BOOST_AUTO_TEST_CASE(WriteTimeout) // Test echo with a minimal timeout std::shared_ptr sentDataA(new LongSendData(34, SHORT_OPERATION_TIME)); - std::shared_ptr recvData = c.callSync(1, sentDataA, TIMEOUT); + std::shared_ptr recvData = c.callSync(1, sentDataA, TIMEOUT); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentDataA->intVal); // Test timeout on write std::shared_ptr sentDataB(new LongSendData(34, LONG_OPERATION_TIME)); - BOOST_CHECK_THROW((c.callSync(1, sentDataB, TIMEOUT)), IPCTimeoutException); + BOOST_CHECK_THROW((c.callSync(1, sentDataB, TIMEOUT)), IPCTimeoutException); } BOOST_AUTO_TEST_CASE(AddSignalInRuntime) { - utils::Latch latchA; - utils::Latch latchB; + ValueLatch> recvDataLatchA; + ValueLatch> recvDataLatchB; Service s(socketPath); Client c(socketPath); connect(s, c); - auto handlerA = [&latchA](const FileDescriptor, std::shared_ptr&) { - latchA.set(); + auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + recvDataLatchA.set(data); }; - auto handlerB = [&latchB](const FileDescriptor, std::shared_ptr&) { - latchB.set(); + auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + recvDataLatchB.set(data); }; - c.setSignalHandler(1, handlerA); - c.setSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); // Wait for the signals to propagate to the Service std::this_thread::sleep_for(std::chrono::milliseconds(2 * TIMEOUT)); - auto data = std::make_shared(1); - s.signal(2, data); - s.signal(1, data); + auto sendDataA = std::make_shared(1); + auto sendDataB = std::make_shared(2); + s.signal(2, sendDataB); + s.signal(1, sendDataA); // Wait for the signals to arrive - BOOST_CHECK(latchA.wait(TIMEOUT) && latchB.wait(TIMEOUT)); + std::shared_ptr recvDataA(recvDataLatchA.get(TIMEOUT)); + std::shared_ptr recvDataB(recvDataLatchB.get(TIMEOUT)); + BOOST_CHECK_EQUAL(recvDataA->intVal, sendDataA->intVal); + BOOST_CHECK_EQUAL(recvDataB->intVal, sendDataB->intVal); } BOOST_AUTO_TEST_CASE(AddSignalOffline) { - utils::Latch latchA; - utils::Latch latchB; + ValueLatch> recvDataLatchA; + ValueLatch> recvDataLatchB; Service s(socketPath); Client c(socketPath); - auto handlerA = [&latchA](const FileDescriptor, std::shared_ptr&) { - latchA.set(); + auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + recvDataLatchA.set(data); }; - auto handlerB = [&latchB](const FileDescriptor, std::shared_ptr&) { - latchB.set(); + auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + recvDataLatchB.set(data); }; - c.setSignalHandler(1, handlerA); - c.setSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); connect(s, c); // Wait for the information about the signals to propagate std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); - auto data = std::make_shared(1); - s.signal(2, data); - s.signal(1, data); + + auto sendDataA = std::make_shared(1); + auto sendDataB = std::make_shared(2); + s.signal(2, sendDataB); + s.signal(1, sendDataA); // Wait for the signals to arrive - BOOST_CHECK(latchA.wait(TIMEOUT) && latchB.wait(TIMEOUT)); + std::shared_ptr recvDataA(recvDataLatchA.get(TIMEOUT)); + std::shared_ptr recvDataB(recvDataLatchB.get(TIMEOUT)); + BOOST_CHECK_EQUAL(recvDataA->intVal, sendDataA->intVal); + BOOST_CHECK_EQUAL(recvDataB->intVal, sendDataB->intVal); } @@ -560,16 +578,16 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { l.set(); }; IPCGSource::Pointer serviceGSource; Service s(socketPath); - s.setMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); - s.setSignalHandler(2, signalHandler); + s.setSignalHandler(2, signalHandler); connectServiceGSource(s, c); @@ -587,7 +605,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { l.set(); }; @@ -596,8 +614,8 @@ BOOST_AUTO_TEST_CASE(ClientGSource) IPCGSource::Pointer clientGSource; Client c(socketPath); - c.setMethodHandler(1, echoCallback); - c.setSignalHandler(2, signalHandler); + c.setMethodHandler(1, echoCallback); + c.setSignalHandler(2, signalHandler); FileDescriptor peerFD = connectClientGSource(s, c); @@ -616,7 +634,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) // // Setup Service and many Clients // Service s(socketPath); -// s.setMethodHandler(1, echoCallback); +// s.setMethodHandler(1, echoCallback); // s.start(); // std::list clients; @@ -632,7 +650,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) // for (auto it = clients.begin(); it != clients.end(); ++it) { // try { // std::shared_ptr sentData(new SendData(generator())); -// std::shared_ptr recvData = it->callSync(1, sentData); +// std::shared_ptr recvData = it->callSync(1, sentData); // BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); // } catch (...) {} // } -- 2.7.4 From 849928b8d50b923e5ff5959de68bfc642da135fa Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 26 Jan 2015 15:40:57 +0100 Subject: [PATCH 06/16] Add list and remove to ZoneProvision class [Bug/Feature] Ability to list and remove provision [Cause] N/A [Solution] N/A [Verification] Build, run tests Change-Id: I3e3a566dd00298d4111fb9a3b5ec6d2351774ac7 --- server/zone-provision.cpp | 106 ++++++++++++++++++++++---- server/zone-provision.hpp | 42 ++++++---- server/zone.cpp | 28 +++---- server/zone.hpp | 22 +++--- tests/unit_tests/server/ut-zone-provision.cpp | 69 +++++++++++++++++ 5 files changed, 214 insertions(+), 53 deletions(-) diff --git a/server/zone-provision.cpp b/server/zone-provision.cpp index 928d887..861a506 100644 --- a/server/zone-provision.cpp +++ b/server/zone-provision.cpp @@ -36,6 +36,7 @@ #include #include +#include #include namespace fs = boost::filesystem; @@ -65,42 +66,53 @@ void ZoneProvision::saveProvisioningConfig() config::saveToKVStore(mDbPath, mProvisioningConfig, mDbPrefix); } -void ZoneProvision::declareProvision(ZoneProvisioningConfig::Provision&& provision) +std::string ZoneProvision::declareProvision(ZoneProvisioningConfig::Provision&& provision) { + std::string id = getId(provision); + auto it = std::find_if(mProvisioningConfig.provisions.begin(), + mProvisioningConfig.provisions.end(), + [&](const ZoneProvisioningConfig::Provision& provision) { + return getId(provision) == id; + }); + if (it != mProvisioningConfig.provisions.end()) { + LOGE("Can't add provision. It already exists: " << id); + throw UtilsException("Provision already exists"); + } mProvisioningConfig.provisions.push_back(std::move(provision)); saveProvisioningConfig(); + return id; } -void ZoneProvision::declareFile(const int32_t& type, - const std::string& path, - const int32_t& flags, - const int32_t& mode) +std::string ZoneProvision::declareFile(const int32_t& type, + const std::string& path, + const int32_t& flags, + const int32_t& mode) { ZoneProvisioningConfig::Provision provision; provision.set(ZoneProvisioningConfig::File({type, path, flags, mode})); - declareProvision(std::move(provision)); + return declareProvision(std::move(provision)); } -void ZoneProvision::declareMount(const std::string& source, - const std::string& target, - const std::string& type, - const int64_t& flags, - const std::string& data) +std::string ZoneProvision::declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t& flags, + const std::string& data) { ZoneProvisioningConfig::Provision provision; provision.set(ZoneProvisioningConfig::Mount({source, target, type, flags, data})); - declareProvision(std::move(provision)); + return declareProvision(std::move(provision)); } -void ZoneProvision::declareLink(const std::string& source, - const std::string& target) +std::string ZoneProvision::declareLink(const std::string& source, + const std::string& target) { ZoneProvisioningConfig::Provision provision; provision.set(ZoneProvisioningConfig::Link({source, target})); - declareProvision(std::move(provision)); + return declareProvision(std::move(provision)); } void ZoneProvision::start() noexcept @@ -138,6 +150,31 @@ void ZoneProvision::stop() noexcept }); } +std::vector ZoneProvision::list() const +{ + std::vector items; + for (const auto& provision : mProvisioningConfig.provisions) { + items.push_back(getId(provision)); + } + return items; +} + +void ZoneProvision::remove(const std::string& item) +{ + + const auto it = std::find_if(mProvisioningConfig.provisions.begin(), + mProvisioningConfig.provisions.end(), + [&](const ZoneProvisioningConfig::Provision& provision) { + return getId(provision) == item; + }); + if (it == mProvisioningConfig.provisions.end()) { + throw UtilsException("Can't find provision"); + } + + mProvisioningConfig.provisions.erase(it); + LOGI("Provision removed: " << item); +} + void ZoneProvision::file(const ZoneProvisioningConfig::File& config) { bool ret = false; @@ -216,4 +253,43 @@ void ZoneProvision::link(const ZoneProvisioningConfig::Link& config) throw UtilsException("Failed to hard link: path prefix is not valid"); } +std::string ZoneProvision::getId(const ZoneProvisioningConfig::File& file) const +{ + //TODO output of type,flags and mode should be more user friendly + return "file " + + file.path + " " + + std::to_string(file.type) + " " + + std::to_string(file.flags) + " " + + std::to_string(file.mode); +} + +std::string ZoneProvision::getId(const ZoneProvisioningConfig::Mount& mount) const +{ + //TODO output of flags should be more user friendly + return "mount " + + mount.source + " " + + mount.target + " " + + mount.type + " " + + std::to_string(mount.flags) + " " + + mount.data; +} + +std::string ZoneProvision::getId(const ZoneProvisioningConfig::Link& link) const +{ + return "link " + link.source + " " + link.target; +} + +std::string ZoneProvision::getId(const ZoneProvisioningConfig::Provision& provision) const +{ + using namespace vasum; + if (provision.is()) { + return getId(provision.as()); + } else if (provision.is()) { + return getId(provision.as()); + } else if (provision.is()) { + return getId(provision.as()); + } + throw UtilsException("Unknown provision type"); +} + } // namespace vasum diff --git a/server/zone-provision.hpp b/server/zone-provision.hpp index f6933db..2f123ae 100644 --- a/server/zone-provision.hpp +++ b/server/zone-provision.hpp @@ -64,27 +64,39 @@ public: /** * Declare file, directory or pipe that will be created while zone startup */ - void declareFile(const int32_t& type, - const std::string& path, - const int32_t& flags, - const int32_t& mode); + std::string declareFile(const int32_t& type, + const std::string& path, + const int32_t& flags, + const int32_t& mode); /** * Declare mount that will be created while zone startup */ - void declareMount(const std::string& source, - const std::string& target, - const std::string& type, - const int64_t& flags, - const std::string& data); + std::string declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t& flags, + const std::string& data); /** * Declare link that will be created while zone startup */ - void declareLink(const std::string& source, - const std::string& target); + std::string declareLink(const std::string& source, + const std::string& target); void start() noexcept; void stop() noexcept; + /** + * List all provisioned resources + */ + std::vector list() const; + + /** + * Remove resource + * + * @param item resource to be removed (as in list()) + */ + void remove(const std::string& item); + private: ZoneProvisioningConfig mProvisioningConfig; std::string mRootPath; @@ -94,14 +106,18 @@ private: std::list mProvisioned; void saveProvisioningConfig(); - void declareProvision(ZoneProvisioningConfig::Provision&& provision); + std::string declareProvision(ZoneProvisioningConfig::Provision&& provision); void mount(const ZoneProvisioningConfig::Mount& config); void umount(const ZoneProvisioningConfig::Mount& config); void file(const ZoneProvisioningConfig::File& config); void link(const ZoneProvisioningConfig::Link& config); -}; + std::string getId(const ZoneProvisioningConfig::File& file) const; + std::string getId(const ZoneProvisioningConfig::Mount& mount) const; + std::string getId(const ZoneProvisioningConfig::Link& link) const; + std::string getId(const ZoneProvisioningConfig::Provision& provision) const; +}; } // namespace vasum diff --git a/server/zone.cpp b/server/zone.cpp index fbbd819..c3f6991 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -381,27 +381,27 @@ void Zone::proxyCallAsync(const std::string& busName, } } -void Zone::declareFile(const int32_t& type, - const std::string& path, - const int32_t& flags, - const int32_t& mode) +std::string Zone::declareFile(const int32_t& type, + const std::string& path, + const int32_t& flags, + const int32_t& mode) { - mProvision->declareFile(type, path, flags, mode); + return mProvision->declareFile(type, path, flags, mode); } -void Zone::declareMount(const std::string& source, - const std::string& target, - const std::string& type, - const int64_t& flags, - const std::string& data) +std::string Zone::declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t& flags, + const std::string& data) { - mProvision->declareMount(source, target, type, flags, data); + return mProvision->declareMount(source, target, type, flags, data); } -void Zone::declareLink(const std::string& source, - const std::string& target) +std::string Zone::declareLink(const std::string& source, + const std::string& target) { - mProvision->declareLink(source, target); + return mProvision->declareLink(source, target); } } // namespace vasum diff --git a/server/zone.hpp b/server/zone.hpp index 2eab7f3..8cd3535 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -230,23 +230,23 @@ public: /** * Declare file, directory or pipe that will be created while zone startup */ - void declareFile(const int32_t& type, - const std::string& path, - const int32_t& flags, - const int32_t& mode); + std::string declareFile(const int32_t& type, + const std::string& path, + const int32_t& flags, + const int32_t& mode); /** * Declare mount that will be created while zone startup */ - void declareMount(const std::string& source, - const std::string& target, - const std::string& type, - const int64_t& flags, - const std::string& data); + std::string declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t& flags, + const std::string& data); /** * Declare link that will be created while zone startup */ - void declareLink(const std::string& source, - const std::string& target); + std::string declareLink(const std::string& source, + const std::string& target); /** * Get zone root path diff --git a/tests/unit_tests/server/ut-zone-provision.cpp b/tests/unit_tests/server/ut-zone-provision.cpp index c488c09..9038fd4 100644 --- a/tests/unit_tests/server/ut-zone-provision.cpp +++ b/tests/unit_tests/server/ut-zone-provision.cpp @@ -89,6 +89,12 @@ struct Fixture { } }; +std::function expectedMessage(const std::string& message) { + return [=](const std::exception& e) { + return e.what() == message; + }; +} + } // namespace @@ -257,6 +263,9 @@ BOOST_AUTO_TEST_CASE(DeclareMountTest) ZoneProvision zoneProvision = create({}); zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake"); zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"); + BOOST_CHECK_EXCEPTION(zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"), + UtilsException, + expectedMessage("Provision already exists")); ZoneProvisioningConfig config; load(config); @@ -338,4 +347,64 @@ BOOST_AUTO_TEST_CASE(ProvisionedAlreadyTest) zoneProvision.stop(); } +BOOST_AUTO_TEST_CASE(ListTest) +{ + std::vector expected; + ZoneProvision zoneProvision = create({}); + + zoneProvision.declareFile(1, "path", 0747, 0777); + zoneProvision.declareFile(2, "path", 0747, 0777); + expected.push_back("file path 1 " + std::to_string(0747) + " " + std::to_string(0777)); + expected.push_back("file path 2 " + std::to_string(0747) + " " + std::to_string(0777)); + + zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake1"); + zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake2"); + expected.push_back("mount /fake/path1 /fake/path2 tmpfs " + std::to_string(077) + " fake1"); + expected.push_back("mount /fake/path1 /fake/path2 tmpfs " + std::to_string(077) + " fake2"); + + zoneProvision.declareLink("/fake/path1", "/fake/path3"); + zoneProvision.declareLink("/fake/path2", "/fake/path4"); + expected.push_back("link /fake/path1 /fake/path3"); + expected.push_back("link /fake/path2 /fake/path4"); + + const std::vector provisions = zoneProvision.list(); + BOOST_REQUIRE_EQUAL(provisions.size(), expected.size()); + auto provision = provisions.cbegin(); + for (const auto& item : expected) { + BOOST_CHECK_EQUAL(item, *(provision++)); + } +} + +BOOST_AUTO_TEST_CASE(RemoveTest) +{ + std::vector expected; + ZoneProvision zoneProvision = create({}); + + zoneProvision.declareFile(1, "path", 0747, 0777); + zoneProvision.declareFile(2, "path", 0747, 0777); + expected.push_back("file path 2 " + std::to_string(0747) + " " + std::to_string(0777)); + + zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake1"); + zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake2"); + expected.push_back("mount /fake/path1 /fake/path2 tmpfs " + std::to_string(077) + " fake1"); + + zoneProvision.declareLink("/fake/path1", "/fake/path3"); + zoneProvision.declareLink("/fake/path2", "/fake/path4"); + expected.push_back("link /fake/path1 /fake/path3"); + + zoneProvision.remove("file path 1 " + std::to_string(0747) + " " + std::to_string(0777)); + zoneProvision.remove("mount /fake/path1 /fake/path2 tmpfs " + std::to_string(077) + " fake2"); + zoneProvision.remove("link /fake/path2 /fake/path4"); + BOOST_CHECK_EXCEPTION(zoneProvision.remove("link /fake/path_fake /fake/path2"), + UtilsException, + expectedMessage("Can't find provision")); + + const std::vector provisions = zoneProvision.list(); + BOOST_REQUIRE_EQUAL(provisions.size(), expected.size()); + auto provision = provisions.cbegin(); + for (const auto& item : expected) { + BOOST_CHECK_EQUAL(item, *(provision++)); + } +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 3680abcc3097cfdccc1245cd7ae5814e56ac236e Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Tue, 27 Jan 2015 16:13:03 +0100 Subject: [PATCH 07/16] Fix focus, defaultId, foregroundId logic [Bug/Feature] Buggy focus logic. DefaultId, foregroundId does not work after implementing dynamic zone adding and removing. [Cause] N/A [Solution] Update focus after remove, pause and stop zone. DefaultId moved to dynamic config. ForegroundId removed from config. [Verification] Build, run tests, run daemon and check focus after adding, pausing, removing zones, switching zones. Change-Id: I325e501242b747802da07b103ccba4c20891138e --- common/config.hpp | 1 + server/configs/daemon.conf.in | 1 - server/host-dbus-definitions.hpp | 2 +- server/zones-manager-config.hpp | 20 +-- server/zones-manager.cpp | 181 ++++++++++++++------- server/zones-manager.hpp | 5 +- .../configs/ut-client/test-dbus-daemon.conf.in | 1 - tests/unit_tests/server/configs/CMakeLists.txt | 4 - .../server/configs/ut-server/buggy-daemon.conf.in | 1 - .../server/configs/ut-server/test-daemon.conf.in | 1 - .../configs/ut-zones-manager/buggy-daemon.conf.in | 1 - .../ut-zones-manager/buggy-default-daemon.conf.in | 18 -- .../buggy-foreground-daemon.conf.in | 18 -- .../ut-zones-manager/empty-dbus-daemon.conf.in | 1 - .../configs/ut-zones-manager/test-daemon.conf.in | 1 - .../ut-zones-manager/test-dbus-daemon.conf.in | 1 - tests/unit_tests/server/ut-zones-manager.cpp | 53 +++--- 17 files changed, 159 insertions(+), 151 deletions(-) delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/buggy-default-daemon.conf.in delete mode 100644 tests/unit_tests/server/configs/ut-zones-manager/buggy-foreground-daemon.conf.in diff --git a/common/config.hpp b/common/config.hpp index 0721de4..753430e 100644 --- a/common/config.hpp +++ b/common/config.hpp @@ -55,6 +55,7 @@ #define final #define override #define thread_local __thread // use GCC extension instead of C++11 +#define steady_clock monotonic_clock #endif // GCC_VERSION < 40700 #endif // GCC_VERSION diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index b7d9c87..ea2d457 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -6,7 +6,6 @@ "zoneTemplatePath" : "/etc/vasum/templates/template.conf", "zoneNewConfigPrefix" : "/var/lib/vasum", "runMountPointPrefix" : "/var/run/zones", - "foregroundId" : "", "defaultId" : "", "lxcTemplatePrefix" : "/etc/vasum/lxc-templates", "inputConfig" : {"enabled" : true, diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index e17261c..ff13843 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -36,7 +36,7 @@ const std::string BUS_NAME = "org.tizen.vasum.host"; const std::string OBJECT_PATH = "/org/tizen/vasum/host"; const std::string INTERFACE = "org.tizen.vasum.host.manager"; -const std::string ERROR_ZONE_STOPPED = "org.tizen.vasum.host.Error.ZonesStopped"; +const std::string ERROR_ZONE_NOT_RUNNING = "org.tizen.vasum.host.Error.ZonesNotRunning"; const std::string METHOD_GET_ZONE_DBUSES = "GetZoneDbuses"; const std::string METHOD_GET_ZONE_ID_LIST = "GetZoneIds"; diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index ab55762..19da74a 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -44,16 +44,6 @@ struct ZonesManagerConfig { std::string dbPath; /** - * An ID of a currently focused/foreground zone. - */ - std::string foregroundId; - - /** - * An ID of default zone. - */ - std::string defaultId; - - /** * A path where the zones mount points reside. */ std::string zonesPath; @@ -97,8 +87,6 @@ struct ZonesManagerConfig { CONFIG_REGISTER ( dbPath, - foregroundId, - defaultId, zonesPath, zoneImagePath, zoneTemplatePath, @@ -118,9 +106,15 @@ struct ZonesManagerDynamicConfig { */ std::vector zoneConfigs; + /** + * An ID of default zone. + */ + std::string defaultId; + CONFIG_REGISTER ( - zoneConfigs + zoneConfigs, + defaultId ) }; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 99e87ee..fa6ec80 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -156,12 +156,7 @@ ZonesManager::ZonesManager(const std::string& configPath) createZone(utils::createFilePath(mConfig.zoneNewConfigPrefix, zoneConfig)); } - // check if default zone exists, throw ZoneOperationException if not found - if (!mConfig.defaultId.empty() && mZones.find(mConfig.defaultId) == mZones.end()) { - LOGE("Provided default zone ID " << mConfig.defaultId << " is invalid."); - throw ZoneOperationException("Provided default zone ID " + mConfig.defaultId + - " is invalid."); - } + updateDefaultId(); LOGD("ZonesManager object instantiated"); @@ -198,6 +193,29 @@ void ZonesManager::saveDynamicConfig() config::saveToKVStore(mConfig.dbPath, mDynamicConfig, DB_PREFIX); } +void ZonesManager::updateDefaultId() +{ + // TODO add an api to change defaultId + if (mZones.empty() && mDynamicConfig.defaultId.empty()) { + LOGT("Keep empty defaultId"); + return; + } + if (mZones.find(mDynamicConfig.defaultId) != mZones.end()) { + LOGT("Keep " << mDynamicConfig.defaultId << " as defaultId"); + return; + } + + // update + if (mZones.empty()) { + mDynamicConfig.defaultId.clear(); + LOGD("DefaultId cleared"); + } else { + mDynamicConfig.defaultId = mZones.begin()->first; + LOGD("DefaultId changed to " << mDynamicConfig.defaultId); + } + saveDynamicConfig(); +} + void ZonesManager::createZone(const std::string& zoneConfigPath) { LOGT("Creating Zone " << zoneConfigPath); @@ -251,7 +269,6 @@ void ZonesManager::destroyZone(const std::string& zoneId) throw ZoneOperationException("No such zone"); } - // TODO give back the focus it->second->setDestroyOnExit(); mZones.erase(it); @@ -264,14 +281,34 @@ void ZonesManager::destroyZone(const std::string& zoneId) // update dynamic config remove(mDynamicConfig.zoneConfigs, getConfigName(zoneId)); saveDynamicConfig(); + updateDefaultId(); + + refocus(); } void ZonesManager::focus(const std::string& zoneId) { Lock lock(mMutex); + if (zoneId == mActiveZoneId) { + // nothing to do + return; + } + + if (zoneId.empty()) { + LOGI("Focus to: host"); + // give back the focus to the host + // TODO switch to host vt + mActiveZoneId.clear(); + return; + } + + LOGI("Focus to: " << zoneId); + /* try to access the object first to throw immediately if it doesn't exist */ - ZoneMap::mapped_type& foregroundZone = mZones.at(zoneId); + auto& foregroundZone = mZones.at(zoneId); + + assert(foregroundZone->isRunning()); if (!foregroundZone->activateVT()) { LOGE("Failed to activate zones VT. Aborting focus."); @@ -279,12 +316,44 @@ void ZonesManager::focus(const std::string& zoneId) } for (auto& zone : mZones) { - LOGD(zone.second->getId() << ": being sent to background"); - zone.second->goBackground(); + if (zone.first == zoneId) { + LOGD(zone.first << ": being sent to foreground"); + zone.second->goForeground(); + } else { + LOGD(zone.first << ": being sent to background"); + zone.second->goBackground(); + } + } + mActiveZoneId = zoneId; +} + +void ZonesManager::refocus() +{ + Lock lock(mMutex); + + // check if refocus is required + auto oldIter = mZones.find(mActiveZoneId); + if (oldIter != mZones.end() && oldIter->second->isRunning()) { + return; + } + + // try to refocus to defaultId + auto iter = mZones.find(mDynamicConfig.defaultId); + if (iter != mZones.end() && iter->second->isRunning()) { + // focus to default + focus(iter->first); + } else { + // focus to any running or to host if not found + auto zoneIsRunning = [](const ZoneMap::value_type& pair) { + return pair.second->isRunning(); + }; + auto iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); + if (iter == mZones.end()) { + focus(std::string()); + } else { + focus(iter->first); + } } - mConfig.foregroundId = foregroundZone->getId(); - LOGD(mConfig.foregroundId << ": being sent to foreground"); - foregroundZone->goForeground(); } void ZonesManager::startAll() @@ -293,30 +362,11 @@ void ZonesManager::startAll() Lock lock(mMutex); - bool isForegroundFound = false; - for (auto& zone : mZones) { zone.second->start(); - - if (zone.first == mConfig.foregroundId) { - isForegroundFound = true; - LOGI(zone.second->getId() << ": set as the foreground zone"); - zone.second->goForeground(); - } } - if (!isForegroundFound) { - auto foregroundIterator = std::min_element(mZones.begin(), mZones.end(), - [](ZoneMap::value_type &c1, ZoneMap::value_type &c2) { - return c1.second->getPrivilege() < c2.second->getPrivilege(); - }); - - if (foregroundIterator != mZones.end()) { - mConfig.foregroundId = foregroundIterator->second->getId(); - LOGI(mConfig.foregroundId << ": no foreground zone configured, setting one with highest priority"); - foregroundIterator->second->goForeground(); - } - } + refocus(); } void ZonesManager::stopAll() @@ -328,6 +378,8 @@ void ZonesManager::stopAll() for (auto& zone : mZones) { zone.second->stop(); } + + refocus(); } bool ZonesManager::isPaused(const std::string& zoneId) @@ -359,13 +411,15 @@ std::string ZonesManager::getRunningForegroundZoneId() const { Lock lock(mMutex); - for (auto& zone : mZones) { - if (zone.first == mConfig.foregroundId && - zone.second->isRunning()) { - return zone.first; - } + if (!mActiveZoneId.empty() && !mZones.at(mActiveZoneId)->isRunning()) { + // Can zone change its state by itself? + // Maybe when it is shut down by itself? TODO check it + LOGW("Active zone " << mActiveZoneId << " is not running any more!"); + assert(false); + return std::string(); } - return std::string(); + + return mActiveZoneId; } std::string ZonesManager::getNextToForegroundZoneId() @@ -378,22 +432,21 @@ std::string ZonesManager::getNextToForegroundZoneId() } for (auto it = mZones.begin(); it != mZones.end(); ++it) { - if (it->first == mConfig.foregroundId && - it->second->isRunning()) { + if (it->first == mActiveZoneId && it->second->isRunning()) { auto nextIt = std::next(it); if (nextIt != mZones.end()) { return nextIt->first; } } } - return mZones.begin()->first; + return mZones.begin()->first;//TODO fix - check isRunning } void ZonesManager::switchingSequenceMonitorNotify() { LOGI("switchingSequenceMonitorNotify() called"); - auto nextZoneId = getNextToForegroundZoneId(); + std::string nextZoneId = getNextToForegroundZoneId(); if (!nextZoneId.empty()) { focus(nextZoneId); @@ -436,13 +489,15 @@ void ZonesManager::displayOffHandler(const std::string& /*caller*/) // get config of currently set zone and switch if switchToDefaultAfterTimeout is true Lock lock(mMutex); - const std::string activeZoneName = getRunningForegroundZoneId(); - const auto& activeZone = mZones.find(activeZoneName); + auto activeZone = mZones.find(mActiveZoneId); if (activeZone != mZones.end() && - activeZone->second->isSwitchToDefaultAfterTimeoutAllowed()) { - LOGI("Switching to default zone " << mConfig.defaultId); - focus(mConfig.defaultId); + activeZone->second->isSwitchToDefaultAfterTimeoutAllowed() && + !mDynamicConfig.defaultId.empty() && + mZones.at(mDynamicConfig.defaultId)->isRunning()) { + + LOGI("Switching to default zone " << mDynamicConfig.defaultId); + focus(mDynamicConfig.defaultId); } } @@ -630,11 +685,9 @@ void ZonesManager::handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer Lock lock(mMutex); - if (!mConfig.foregroundId.empty() && mZones[mConfig.foregroundId]->isRunning()){ - result->set(g_variant_new("(s)", mConfig.foregroundId.c_str())); - } else { - result->set(g_variant_new("(s)", "")); - } + std::string id = getRunningForegroundZoneId(); + + result->set(g_variant_new("(s)", id.c_str())); } void ZonesManager::handleGetZoneInfoCall(const std::string& id, @@ -651,7 +704,7 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, } const auto& zone = mZones[id]; const char* state; - //TODO: Use the lookup map. + if (zone->isRunning()) { state = "RUNNING"; } else if (zone->isStopped()) { @@ -752,10 +805,10 @@ void ZonesManager::handleSetActiveZoneCall(const std::string& id, return; } - if (zone->second->isStopped()){ - LOGE("Could not activate a stopped zone"); - result->setError(api::host::ERROR_ZONE_STOPPED, - "Could not activate a stopped zone"); + if (!zone->second->isRunning()){ + LOGE("Could not activate stopped or paused zone"); + result->setError(api::host::ERROR_ZONE_NOT_RUNNING, + "Could not activate stopped or paused zone"); return; } @@ -891,6 +944,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, mDynamicConfig.zoneConfigs.push_back(newConfigName); saveDynamicConfig(); + updateDefaultId(); result->setVoid(); } @@ -939,13 +993,19 @@ void ZonesManager::handleShutdownZoneCall(const std::string& id, auto shutdown = [id, result, this] { try { - mZones[id]->stop(); + ZoneMap::mapped_type zone; + { + Lock lock(mMutex); + zone = mZones.at(id); + } + zone->stop(); + refocus(); + result->setVoid(); } catch (ZoneOperationException& e) { LOGE("Error during zone shutdown: " << e.what()); result->setError(api::ERROR_INTERNAL, "Failed to shutdown zone"); return; } - result->setVoid(); }; mWorker->addTask(shutdown); @@ -1008,6 +1068,7 @@ void ZonesManager::handleLockZoneCall(const std::string& id, LOGT("Lock zone"); try { zone.suspend(); + refocus(); } catch (ZoneOperationException& e) { LOGE(e.what()); result->setError(api::ERROR_INTERNAL, e.what()); diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 677b056..72dd952 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -117,11 +117,14 @@ private: // to hold InputMonitor pointer to monitor if zone switching sequence is recognized std::unique_ptr mSwitchingSequenceMonitor; std::unique_ptr mProxyCallPolicy; - typedef std::unordered_map> ZoneMap; + typedef std::unordered_map> ZoneMap;//TODO should keep order of insertions ZoneMap mZones; // map of zones, id is the key + std::string mActiveZoneId; bool mDetachOnExit; void saveDynamicConfig(); + void updateDefaultId(); + void refocus(); void switchingSequenceMonitorNotify(); void generateNewConfig(const std::string& id, const std::string& templatePath, diff --git a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in index 544accc..e0af664 100644 --- a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in +++ b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in @@ -3,7 +3,6 @@ "zoneConfigs" : ["zones/console1-dbus.conf", "zones/console2-dbus.conf", "zones/console3-dbus.conf"], - "foregroundId" : "ut-zones-manager-console1-dbus", "defaultId" : "ut-zones-manager-console1-dbus", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index 596c123..fac9d99 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -50,10 +50,6 @@ CONFIGURE_FILE(ut-zones-manager/test-daemon.conf.in ${CMAKE_BINARY_DIR}/ut-zones-manager/test-daemon.conf @ONLY) CONFIGURE_FILE(ut-zones-manager/buggy-daemon.conf.in ${CMAKE_BINARY_DIR}/ut-zones-manager/buggy-daemon.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/buggy-default-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/buggy-default-daemon.conf @ONLY) -CONFIGURE_FILE(ut-zones-manager/buggy-foreground-daemon.conf.in - ${CMAKE_BINARY_DIR}/ut-zones-manager/buggy-foreground-daemon.conf @ONLY) CONFIGURE_FILE(ut-zones-manager/test-dbus-daemon.conf.in ${CMAKE_BINARY_DIR}/ut-zones-manager/test-dbus-daemon.conf @ONLY) CONFIGURE_FILE(ut-zones-manager/empty-dbus-daemon.conf.in diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in index 9df74dc..bf274de 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in @@ -6,7 +6,6 @@ "zoneTemplatePath" : "no_need_for_templates_in_this_test", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", "runMountPointPrefix" : "", - "foregroundId" : "ut-server-zone1", "defaultId" : "ut-server-zone1", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in index 697a468..e1a67e8 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in @@ -6,7 +6,6 @@ "zoneTemplatePath" : "no_need_for_templates_in_this_test", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-server/", "runMountPointPrefix" : "", - "foregroundId" : "ut-server-zone1", "defaultId" : "ut-server-zone1", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in index 754594f..d07ab4c 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in @@ -2,7 +2,6 @@ "dbPath" : "/tmp/ut-zones/vasum.db", "zoneConfigs" : ["zones/console1.conf", "missing/file/path/missing.conf", "zones/console3.conf"], "runMountPointPrefix" : "", - "foregroundId" : "ut-zones-manager-console1", "defaultId" : "ut-zones-manager-console1", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-default-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-default-daemon.conf.in deleted file mode 100644 index 3eb9e02..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-default-daemon.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1.conf", "zones/console2.conf", "zones/console3.conf"], - "runMountPointPrefix" : "", - "foregroundId" : "ut-zones-manager-console1", - "defaultId" : "in_no_way_there_is_a_valid_id_here", - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-foreground-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-foreground-daemon.conf.in deleted file mode 100644 index 6e02372..0000000 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-foreground-daemon.conf.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dbPath" : "/tmp/ut-zones/vasum.db", - "zoneConfigs" : ["zones/console1.conf", "zones/console2.conf", "zones/console3.conf"], - "runMountPointPrefix" : "", - "foregroundId" : "this_id_does_not_exist", - "defaultId" : "ut-zones-manager-console1", - "zonesPath" : "/tmp/ut-zones", - "zoneImagePath" : "", - "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", - "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", - "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", - "inputConfig" : {"enabled" : false, - "device" : "/dev/doesnotexist", - "code" : 139, - "numberOfEvents" : 2, - "timeWindowMs" : 500}, - "proxyCallRules" : [] -} diff --git a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in index a80be26..943ade9 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in @@ -1,7 +1,6 @@ { "dbPath" : "/tmp/ut-zones/vasum.db", "zoneConfigs" : [], - "foregroundId" : "", "defaultId" : "", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in index 14cea0b..f3cddde 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in @@ -2,7 +2,6 @@ "dbPath" : "/tmp/ut-zones/vasum.db", "zoneConfigs" : ["zones/console1.conf", "zones/console2.conf", "zones/console3.conf"], "runMountPointPrefix" : "", - "foregroundId" : "ut-zones-manager-console1", "defaultId" : "ut-zones-manager-console1", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in index 2a55718..fc47ff9 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in @@ -3,7 +3,6 @@ "zoneConfigs" : ["zones/console1-dbus.conf", "zones/console2-dbus.conf", "zones/console3-dbus.conf"], - "foregroundId" : "ut-zones-manager-console1-dbus", "defaultId" : "ut-zones-manager-console1-dbus", "zonesPath" : "/tmp/ut-zones", "zoneImagePath" : "", diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 5925052..3929c77 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -65,11 +65,10 @@ const std::string TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zon const std::string TEST_DBUS_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/test-dbus-daemon.conf"; const std::string EMPTY_DBUS_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/empty-dbus-daemon.conf"; const std::string BUGGY_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/buggy-daemon.conf"; -const std::string BUGGY_FOREGROUND_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/buggy-foreground-daemon.conf"; -const std::string BUGGY_DEFAULTID_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/buggy-default-daemon.conf"; const std::string TEST_ZONE_CONF_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zones-manager/zones/"; const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; +const int UNEXPECTED_EVENT_TIMEOUT = EVENT_TIMEOUT / 5; const int TEST_DBUS_CONNECTION_ZONES_COUNT = 3; const std::string PREFIX_CONSOLE_NAME = "ut-zones-manager-console"; const std::string TEST_APP_NAME = "testapp"; @@ -438,7 +437,8 @@ private: std::mutex mMutex; std::condition_variable mNameCondition; - bool isHost() const { + bool isHost() const + { return mId == HOST_ID; } @@ -452,12 +452,26 @@ private: } }; -std::function expectedMessage(const std::string& message) { +std::function expectedMessage(const std::string& message) +{ return [=](const std::exception& e) { return e.what() == message; }; } +template +bool spinWaitFor(int timeoutMs, Predicate pred) +{ + auto until = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeoutMs); + while (!pred()) { + if (std::chrono::steady_clock::now() >= until) { + return false; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + return true; +} + struct Fixture { vasum::utils::ScopedGlibLoop mLoop; @@ -499,19 +513,6 @@ BOOST_AUTO_TEST_CASE(StartAllTest) BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console1"); } -BOOST_AUTO_TEST_CASE(BuggyForegroundTest) -{ - ZonesManager cm(BUGGY_FOREGROUND_CONFIG_PATH); - cm.startAll(); - BOOST_CHECK(cm.getRunningForegroundZoneId() == "ut-zones-manager-console2"); -} - -BOOST_AUTO_TEST_CASE(BuggyDefaultTest) -{ - BOOST_REQUIRE_THROW(ZonesManager cm(BUGGY_DEFAULTID_CONFIG_PATH), - ZoneOperationException); -} - BOOST_AUTO_TEST_CASE(StopAllTest) { ZonesManager cm(TEST_CONFIG_PATH); @@ -626,9 +627,6 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) client->setName(fake_power_manager_api::BUS_NAME); } - std::mutex Mutex; - std::unique_lock Lock(Mutex); - std::condition_variable Condition; auto cond = [&cm]() -> bool { return cm.getRunningForegroundZoneId() == "ut-zones-manager-console1-dbus"; }; @@ -645,7 +643,7 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) nullptr); // check if default zone has focus - BOOST_CHECK(Condition.wait_for(Lock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, cond)); } } @@ -761,9 +759,6 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) client->setName(fake_power_manager_api::BUS_NAME); } - std::mutex condMutex; - std::unique_lock condLock(condMutex); - std::condition_variable condition; auto cond = [&cm]() -> bool { return cm.getRunningForegroundZoneId() == "ut-zones-manager-console1-dbus"; }; @@ -779,7 +774,7 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) nullptr); // check if default zone has focus - BOOST_CHECK(condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, cond)); // focus non-default zone with disabled switching cm.focus("ut-zones-manager-console2-dbus"); @@ -791,7 +786,7 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) nullptr); // now default zone should not be focused - BOOST_CHECK(!condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + BOOST_CHECK(!spinWaitFor(UNEXPECTED_EVENT_TIMEOUT, cond)); } } @@ -1048,6 +1043,8 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) cm.startAll(); + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1); + cm.focus(zone3); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone3); // destroy zone2 @@ -1058,7 +1055,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest) // destroy zone3 dbus.callAsyncMethodDestroyZone(zone3, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - //BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1);//TODO fix it + BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1); // destroy zone1 dbus.callAsyncMethodDestroyZone(zone1, resultCallback); @@ -1159,7 +1156,7 @@ BOOST_AUTO_TEST_CASE(LockUnlockZoneTest) "ut-zones-manager-console2-dbus", "ut-zones-manager-console3-dbus"}; - for (std::string& zoneId: zoneIds){ + for (const std::string& zoneId: zoneIds){ dbus.callMethodLockZone(zoneId); BOOST_CHECK(cm.isPaused(zoneId)); dbus.callMethodUnlockZone(zoneId); -- 2.7.4 From 5c9f567e6fc2b39e65f8dc616b4dae3fba117f1c Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Wed, 28 Jan 2015 13:31:50 +0100 Subject: [PATCH 08/16] Compile test of client C API [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build Change-Id: I4c8d33904f9f23db70e8ffc0e6002bf2e3335ee8 --- client/vasum-client.h | 17 ++++++----- tests/unit_tests/CMakeLists.txt | 3 ++ .../unit_tests/client/client-c-api-compile-test.c | 34 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 tests/unit_tests/client/client-c-api-compile-test.c diff --git a/client/vasum-client.h b/client/vasum-client.h index eba04e6..bf15f25 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -80,6 +80,7 @@ finish: #include #include +#include #ifdef __cplusplus extern "C" @@ -109,12 +110,12 @@ typedef VsmString* VsmArrayString; * Completion status of communication function. */ typedef enum { - 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 + 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; /** @@ -653,7 +654,7 @@ VsmStatus vsm_declare_link(VsmClient client, const char *target); -/** @} */ // Host API +/** @} Host API */ /** @@ -722,7 +723,7 @@ VsmStatus vsm_add_notification_callback(VsmClient client, */ VsmStatus vsm_del_notification_callback(VsmClient client, VsmSubscriptionId subscriptionId); -/** @} */ // Zone API +/** @} Zone API */ #ifdef __cplusplus } diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 8b66b09..96ab943 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -32,6 +32,9 @@ LIST(REMOVE_ITEM server_SRCS ${main_SRC}) SET(UT_SERVER_CODENAME "${PROJECT_NAME}-server-unit-tests") ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${common_SRCS} ${server_SRCS} ${client_SRCS}) +## A fake target to test vasum-client C API +ADD_EXECUTABLE("vasum-client-c-api-compile-test" client/client-c-api-compile-test.c) + ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) diff --git a/tests/unit_tests/client/client-c-api-compile-test.c b/tests/unit_tests/client/client-c-api-compile-test.c new file mode 100644 index 0000000..168b8cd --- /dev/null +++ b/tests/unit_tests/client/client-c-api-compile-test.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Compilation test of Vasum Client C API + * + * This API header is already included in vasum-client.cpp, + * although this test is required to: + * - detect missing includes + * - check if it is a pure C API (extern "C" does not guarantee it) + */ + +#include "vasum-client.h" + +int main() { + return 0; +} -- 2.7.4 From 8fe7189dc8d8789e7abd8f80fec3b0fe34a4c069 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Mon, 26 Jan 2015 14:33:01 +0100 Subject: [PATCH 09/16] IPC: Remote error handling [Bug/Feature] Passing errors to callbacks [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: Icbe4df6671144fd34a3bf8b43c4360c2242a6d3e --- common/ipc/client.hpp | 1 + common/ipc/exception.hpp | 48 +++++++++-- common/ipc/internals/method-request.hpp | 12 +-- common/ipc/internals/processor.cpp | 115 ++++++++++++++++++--------- common/ipc/internals/processor.hpp | 136 +++++++++++++++++++++----------- common/ipc/internals/request-queue.hpp | 28 +++++-- common/ipc/internals/result-builder.hpp | 78 ++++++++++++++++++ common/ipc/result.hpp | 74 +++++++++++++++++ common/ipc/service.hpp | 1 + common/ipc/types.cpp | 33 -------- common/ipc/types.hpp | 20 ----- tests/unit_tests/ipc/ut-ipc.cpp | 49 +++++++++--- 12 files changed, 428 insertions(+), 167 deletions(-) create mode 100644 common/ipc/internals/result-builder.hpp create mode 100644 common/ipc/result.hpp diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index eedf81b..1ee44bb 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -28,6 +28,7 @@ #include "ipc/internals/processor.hpp" #include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" +#include "ipc/result.hpp" #include "logger/logger.hpp" #include diff --git a/common/ipc/exception.hpp b/common/ipc/exception.hpp index 794cf21..8e9a7df 100644 --- a/common/ipc/exception.hpp +++ b/common/ipc/exception.hpp @@ -29,35 +29,67 @@ #include "base-exception.hpp" namespace vasum { - +namespace ipc { /** * Base class for exceptions in IPC */ struct IPCException: public VasumException { - IPCException(const std::string& error) : VasumException(error) {} + IPCException(const std::string& message) + : VasumException(message) {} }; struct IPCParsingException: public IPCException { - IPCParsingException(const std::string& error) : IPCException(error) {} + IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") + : IPCException(message) {} }; struct IPCSerializationException: public IPCException { - IPCSerializationException(const std::string& error) : IPCException(error) {} + IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") + : IPCException(message) {} }; struct IPCPeerDisconnectedException: public IPCException { - IPCPeerDisconnectedException(const std::string& error) : IPCException(error) {} + IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") + : IPCException(message) {} }; struct IPCNaughtyPeerException: public IPCException { - IPCNaughtyPeerException(const std::string& error) : IPCException(error) {} + IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") + : IPCException(message) {} +}; + +struct IPCRemovedPeerException: public IPCException { + IPCRemovedPeerException(const std::string& message = "Removing peer") + : IPCException(message) {} +}; + +struct IPCClosingException: public IPCException { + IPCClosingException(const std::string& message = "Closing IPC") + : IPCException(message) {} }; struct IPCTimeoutException: public IPCException { - IPCTimeoutException(const std::string& error) : IPCException(error) {} + IPCTimeoutException(const std::string& message) + : IPCException(message) {} +}; + +struct IPCUserException: public IPCException { + IPCUserException(const int code, const std::string& message) + : IPCException(message), + mCode(code) + {} + + int getCode() const + { + return mCode; + } + +private: + int mCode; }; -} +} // namespace ipc +} // namespace vasum #endif // COMMON_IPC_EXCEPTION_HPP diff --git a/common/ipc/internals/method-request.hpp b/common/ipc/internals/method-request.hpp index 36d3d7a..8ed17c5 100644 --- a/common/ipc/internals/method-request.hpp +++ b/common/ipc/internals/method-request.hpp @@ -25,9 +25,12 @@ #ifndef COMMON_IPC_INTERNALS_METHOD_REQUEST_HPP #define COMMON_IPC_INTERNALS_METHOD_REQUEST_HPP +#include "ipc/internals/result-builder.hpp" #include "ipc/types.hpp" +#include "ipc/result.hpp" #include "logger/logger-scope.hpp" #include "config/manager.hpp" +#include namespace vasum { namespace ipc { @@ -49,7 +52,7 @@ public: std::shared_ptr data; SerializeCallback serialize; ParseCallback parse; - ResultHandler::type process; + ResultBuilderHandler process; private: MethodRequest(const MethodID methodID, const FileDescriptor peerFD) @@ -82,10 +85,9 @@ std::shared_ptr MethodRequest::create(const MethodID methodID, return data; }; - request->process = [process](Status status, std::shared_ptr& data)->void { - LOGS("Method process, status: " << toString(status)); - std::shared_ptr tmpData = std::static_pointer_cast(data); - return process(status, tmpData); + request->process = [process](ResultBuilder & resultBuilder) { + LOGS("Method process"); + process(resultBuilder.build()); }; return request; diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index bdc8a8d..58beca8 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -51,6 +51,7 @@ namespace ipc { const MethodID Processor::RETURN_METHOD_ID = std::numeric_limits::max(); const MethodID Processor::REGISTER_SIGNAL_METHOD_ID = std::numeric_limits::max() - 1; +const MethodID Processor::ERROR_METHOD_ID = std::numeric_limits::max() - 2; Processor::Processor(const std::string& logName, const PeerCallback& newPeerCallback, @@ -66,8 +67,10 @@ Processor::Processor(const std::string& logName, utils::signalBlock(SIGPIPE); using namespace std::placeholders; - setMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID, - std::bind(&Processor::onNewSignals, this, _1, _2)); + setSignalHandlerInternal(REGISTER_SIGNAL_METHOD_ID, + std::bind(&Processor::onNewSignals, this, _1, _2)); + + setSignalHandlerInternal(ERROR_METHOD_ID, std::bind(&Processor::onErrorSignal, this, _1, _2)); } Processor::~Processor() @@ -110,7 +113,7 @@ void Processor::stop() { Lock lock(mStateMutex); auto request = std::make_shared(conditionPtr); - mRequestQueue.push(Event::FINISH, request); + mRequestQueue.pushBack(Event::FINISH, request); } LOGD(mLogPrefix + "Waiting for the Processor to stop"); @@ -158,7 +161,7 @@ FileDescriptor Processor::addPeer(const std::shared_ptr& socketPtr) FileDescriptor peerFD = socketPtr->getFD(); auto request = std::make_shared(peerFD, socketPtr); - mRequestQueue.push(Event::ADD_PEER, request); + mRequestQueue.pushBack(Event::ADD_PEER, request); LOGI(mLogPrefix + "Add Peer Request. Id: " << peerFD); @@ -182,7 +185,7 @@ void Processor::removePeer(const FileDescriptor peerFD) { Lock lock(mStateMutex); auto request = std::make_shared(peerFD, conditionPtr); - mRequestQueue.push(Event::REMOVE_PEER, request); + mRequestQueue.pushBack(Event::REMOVE_PEER, request); } auto isPeerDeleted = [&peerFD, this]()->bool { @@ -193,7 +196,7 @@ void Processor::removePeer(const FileDescriptor peerFD) conditionPtr->wait(lock, isPeerDeleted); } -void Processor::removePeerInternal(const FileDescriptor peerFD, Status status) +void Processor::removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr) { LOGS(mLogPrefix + "Processor removePeerInternal peerFD: " << peerFD); LOGI(mLogPrefix + "Removing peer. peerFD: " << peerFD); @@ -214,10 +217,10 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, Status status) } // Erase associated return value callbacks - std::shared_ptr data; for (auto it = mReturnCallbacks.begin(); it != mReturnCallbacks.end();) { if (it->second.peerFD == peerFD) { - IGNORE_EXCEPTIONS(it->second.process(status, data)); + ResultBuilder resultBuilder(exceptionPtr); + IGNORE_EXCEPTIONS(it->second.process(resultBuilder)); it = mReturnCallbacks.erase(it); } else { ++it; @@ -312,7 +315,8 @@ bool Processor::handleLostConnections() if (mFDs[i].revents & POLLHUP) { LOGI(mLogPrefix + "Lost connection to peer: " << mFDs[i].fd); mFDs[i].revents &= ~(POLLHUP); - removePeerInternal(mFDs[i].fd, Status::PEER_DISCONNECTED); + removePeerInternal(mFDs[i].fd, + std::make_exception_ptr(IPCPeerDisconnectedException())); isPeerRemoved = true; } } @@ -324,7 +328,8 @@ bool Processor::handleLostConnections() bool Processor::handleLostConnection(const FileDescriptor peerFD) { Lock lock(mStateMutex); - removePeerInternal(peerFD, Status::PEER_DISCONNECTED); + removePeerInternal(peerFD, + std::make_exception_ptr(IPCPeerDisconnectedException())); return true; } @@ -367,7 +372,8 @@ bool Processor::handleInput(const FileDescriptor peerFD) } catch (const IPCException& e) { LOGE(mLogPrefix + "Error during reading the socket"); - removePeerInternal(socketPtr->getFD(), Status::NAUGHTY_PEER); + removePeerInternal(socketPtr->getFD(), + std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -388,23 +394,33 @@ bool Processor::handleInput(const FileDescriptor peerFD) } else { // Nothing LOGW(mLogPrefix + "No method or signal callback for methodID: " << methodID); - removePeerInternal(socketPtr->getFD(), Status::NAUGHTY_PEER); + removePeerInternal(socketPtr->getFD(), + std::make_exception_ptr(IPCNaughtyPeerException())); return true; } } } } -std::shared_ptr Processor::onNewSignals(const FileDescriptor peerFD, - std::shared_ptr& data) +void Processor::onNewSignals(const FileDescriptor peerFD, + std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onNewSignals peerFD: " << peerFD); for (const MethodID methodID : data->ids) { mSignalsPeers[methodID].push_back(peerFD); } +} - return std::make_shared(); +void Processor::onErrorSignal(const FileDescriptor, std::shared_ptr& data) +{ + LOGS(mLogPrefix + "Processor onErrorSignal messageID: " << data->messageID); + + ReturnCallbacks returnCallbacks = std::move(mReturnCallbacks.at(data->messageID)); + mReturnCallbacks.erase(data->messageID); + + ResultBuilder resultBuilder(std::make_exception_ptr(IPCUserException(data->code, data->message))); + IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); } bool Processor::onReturnValue(const Socket& socket, @@ -420,7 +436,8 @@ bool Processor::onReturnValue(const Socket& socket, mReturnCallbacks.erase(messageID); } catch (const std::out_of_range&) { LOGW(mLogPrefix + "No return callback for messageID: " << messageID); - removePeerInternal(socket.getFD(), Status::NAUGHTY_PEER); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -430,13 +447,16 @@ bool Processor::onReturnValue(const Socket& socket, data = returnCallbacks.parse(socket.getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - IGNORE_EXCEPTIONS(returnCallbacks.process(Status::PARSING_ERROR, data)); - removePeerInternal(socket.getFD(), Status::PARSING_ERROR); + ResultBuilder resultBuilder(std::make_exception_ptr(IPCParsingException())); + IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCParsingException())); return true; } // LOGT(mLogPrefix + "Process return value callback for messageID: " << messageID); - IGNORE_EXCEPTIONS(returnCallbacks.process(Status::OK, data)); + ResultBuilder resultBuilder(data); + IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); // LOGT(mLogPrefix + "Return value for messageID: " << messageID << " processed"); return false; @@ -457,16 +477,22 @@ bool Processor::onRemoteSignal(const Socket& socket, data = signalCallbacks->parse(socket.getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), Status::PARSING_ERROR); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCParsingException())); return true; } // LOGT(mLogPrefix + "Signal callback for methodID: " << methodID << "; messageID: " << messageID); try { signalCallbacks->signal(socket.getFD(), data); + } catch (const IPCUserException& e) { + LOGW("Discarded user's exception"); + return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), Status::NAUGHTY_PEER); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCNaughtyPeerException())); + return true; } @@ -487,7 +513,8 @@ bool Processor::onRemoteCall(const Socket& socket, data = methodCallbacks->parse(socket.getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), Status::PARSING_ERROR); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCParsingException())); return true; } @@ -495,9 +522,15 @@ bool Processor::onRemoteCall(const Socket& socket, std::shared_ptr returnData; try { returnData = methodCallbacks->method(socket.getFD(), data); + } catch (const IPCUserException& e) { + LOGW("User's exception"); + auto data = std::make_shared(messageID, e.getCode(), e.what()); + signalInternal(ERROR_METHOD_ID, socket.getFD(), data); + return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), Status::NAUGHTY_PEER); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -510,7 +543,9 @@ bool Processor::onRemoteCall(const Socket& socket, methodCallbacks->serialize(socket.getFD(), returnData); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during serialization: " << e.what()); - removePeerInternal(socket.getFD(), Status::SERIALIZATION_ERROR); + removePeerInternal(socket.getFD(), + std::make_exception_ptr(IPCSerializationException())); + return true; } @@ -549,7 +584,8 @@ bool Processor::onMethodRequest(MethodRequest& request) LOGE(mLogPrefix + "Peer disconnected. No socket with a peerFD: " << request.peerFD); // Pass the error to the processing callback - IGNORE_EXCEPTIONS(request.process(Status::PEER_DISCONNECTED, request.data)); + ResultBuilder resultBuilder(std::make_exception_ptr(IPCPeerDisconnectedException())); + IGNORE_EXCEPTIONS(request.process(resultBuilder)); return false; } @@ -571,12 +607,15 @@ bool Processor::onMethodRequest(MethodRequest& request) } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a method: " << e.what()); - // Inform about the error, - IGNORE_EXCEPTIONS(mReturnCallbacks[request.messageID].process(Status::SERIALIZATION_ERROR, request.data)); + // Inform about the error + ResultBuilder resultBuilder(std::make_exception_ptr(IPCSerializationException())); + IGNORE_EXCEPTIONS(mReturnCallbacks[request.messageID].process(resultBuilder)); mReturnCallbacks.erase(request.messageID); - removePeerInternal(request.peerFD, Status::SERIALIZATION_ERROR); + removePeerInternal(request.peerFD, + std::make_exception_ptr(IPCSerializationException())); + return true; @@ -607,7 +646,9 @@ bool Processor::onSignalRequest(SignalRequest& request) } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a signal: " << e.what()); - removePeerInternal(request.peerFD, Status::SERIALIZATION_ERROR); + removePeerInternal(request.peerFD, + std::make_exception_ptr(IPCSerializationException())); + return true; } @@ -635,11 +676,10 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) for (const auto kv : mSignalsCallbacks) { ids.push_back(kv.first); } - auto data = std::make_shared(ids); - callAsync(REGISTER_SIGNAL_METHOD_ID, - request.peerFD, - data, - discardResultHandler); + auto data = std::make_shared(ids); + signalInternal(REGISTER_SIGNAL_METHOD_ID, + request.peerFD, + data); resetPolling(); @@ -658,7 +698,9 @@ bool Processor::onRemovePeerRequest(RemovePeerRequest& request) { LOGS(mLogPrefix + "Processor onRemovePeer"); - removePeerInternal(request.peerFD, Status::REMOVED_PEER); + removePeerInternal(request.peerFD, + std::make_exception_ptr(IPCRemovedPeerException())); + request.conditionPtr->notify_all(); return true; @@ -676,7 +718,8 @@ bool Processor::onFinishRequest(FinishRequest& request) switch (request.requestID) { case Event::METHOD: { auto requestPtr = request.get(); - IGNORE_EXCEPTIONS(requestPtr->process(Status::CLOSING, requestPtr->data)); + ResultBuilder resultBuilder(std::make_exception_ptr(IPCClosingException())); + IGNORE_EXCEPTIONS(requestPtr->process(resultBuilder)); break; } case Event::REMOVE_PEER: { diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index c3bcc6b..b6bd615 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -25,6 +25,7 @@ #ifndef COMMON_IPC_INTERNALS_PROCESSOR_HPP #define COMMON_IPC_INTERNALS_PROCESSOR_HPP +#include "ipc/internals/result-builder.hpp" #include "ipc/internals/socket.hpp" #include "ipc/internals/request-queue.hpp" #include "ipc/internals/method-request.hpp" @@ -55,7 +56,6 @@ namespace vasum { namespace ipc { const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500; -const unsigned int DEFAULT_METHOD_TIMEOUT = 1000; /** * This class wraps communication via UX sockets @@ -84,6 +84,7 @@ const unsigned int DEFAULT_METHOD_TIMEOUT = 1000; * - no new events added after stop() called * - when using IPCGSource: addFD and removeFD can be called from addPeer removePeer callbacks, but * there is no mechanism to ensure the IPCSource exists.. therefore SIGSEGV :) +* - remove recursive mutex * */ class Processor { @@ -97,7 +98,6 @@ private: }; public: - friend std::ostream& operator<<(std::ostream& os, const Processor::Event& event); /** @@ -111,6 +111,11 @@ public: static const MethodID REGISTER_SIGNAL_METHOD_ID; /** + * Error return message + */ + static const MethodID ERROR_METHOD_ID; + + /** * Constructs the Processor, but doesn't start it. * The object is ready to add methods. * @@ -304,9 +309,9 @@ private: CONFIG_REGISTER_EMPTY }; - struct RegisterSignalsMessage { - RegisterSignalsMessage() = default; - RegisterSignalsMessage(const std::vector ids) + struct RegisterSignalsProtocolMessage { + RegisterSignalsProtocolMessage() = default; + RegisterSignalsProtocolMessage(const std::vector ids) : ids(ids) {} std::vector ids; @@ -317,6 +322,23 @@ private: ) }; + struct ErrorProtocolMessage { + ErrorProtocolMessage() = default; + ErrorProtocolMessage(const MessageID messageID, const int code, const std::string& message) + : messageID(messageID), code(code), message(message) {} + + MessageID messageID; + int code; + std::string message; + + CONFIG_REGISTER + ( + messageID, + code, + message + ) + }; + struct MethodHandlers { MethodHandlers(const MethodHandlers& other) = delete; MethodHandlers& operator=(const MethodHandlers&) = delete; @@ -347,12 +369,12 @@ private: ReturnCallbacks(ReturnCallbacks&&) = default; ReturnCallbacks& operator=(ReturnCallbacks &&) = default; - ReturnCallbacks(FileDescriptor peerFD, const ParseCallback& parse, const ResultHandler::type& process) + ReturnCallbacks(FileDescriptor peerFD, const ParseCallback& parse, const ResultBuilderHandler& process) : peerFD(peerFD), parse(parse), process(process) {} FileDescriptor peerFD; ParseCallback parse; - ResultHandler::type process; + ResultBuilderHandler process; }; std::string mLogPrefix; @@ -386,7 +408,13 @@ private: const typename MethodHandler::type& process); template - static void discardResultHandler(Status, std::shared_ptr&) {} + void setSignalHandlerInternal(const MethodID methodID, + const typename SignalHandler::type& handler); + + template + void signalInternal(const MethodID methodID, + const FileDescriptor peerFD, + const std::shared_ptr& data); void run(); @@ -412,10 +440,13 @@ private: std::shared_ptr signalCallbacks); void resetPolling(); FileDescriptor getNextFileDescriptor(); - void removePeerInternal(const FileDescriptor peerFD, Status status); + void removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr); + + void onNewSignals(const FileDescriptor peerFD, + std::shared_ptr& data); - std::shared_ptr onNewSignals(const FileDescriptor peerFD, - std::shared_ptr& data); + void onErrorSignal(const FileDescriptor peerFD, + std::shared_ptr& data); }; @@ -441,10 +472,7 @@ void Processor::setMethodHandlerInternal(const MethodID methodID, return method(peerFD, tmpData); }; - { - Lock lock(mStateMutex); - mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall)); - } + mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall)); } template @@ -464,12 +492,33 @@ void Processor::setMethodHandler(const MethodID methodID, throw IPCException("MethodID used by a signal: " + std::to_string(methodID)); } - setMethodHandlerInternal(methodID, method); + setMethodHandlerInternal(methodID, method); } } template +void Processor::setSignalHandlerInternal(const MethodID methodID, + const typename SignalHandler::type& handler) +{ + SignalHandlers signalCall; + + signalCall.parse = [](const int fd)->std::shared_ptr { + std::shared_ptr dataToFill(new ReceivedDataType()); + config::loadFromFD(fd, *dataToFill); + return dataToFill; + }; + + signalCall.signal = [handler](const FileDescriptor peerFD, std::shared_ptr& dataReceived) { + std::shared_ptr tmpData = std::static_pointer_cast(dataReceived); + handler(peerFD, tmpData); + }; + + mSignalsCallbacks[methodID] = std::make_shared(std::move(signalCall)); +} + + +template void Processor::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { @@ -478,8 +527,9 @@ void Processor::setSignalHandler(const MethodID methodID, throw IPCException("Forbidden methodID: " + std::to_string(methodID)); } - std::shared_ptr data; + std::shared_ptr data; std::vector peerFDs; + { Lock lock(mStateMutex); @@ -489,24 +539,11 @@ void Processor::setSignalHandler(const MethodID methodID, throw IPCException("MethodID used by a method: " + std::to_string(methodID)); } - SignalHandlers signalCall; - - signalCall.parse = [](const int fd)->std::shared_ptr { - std::shared_ptr data(new ReceivedDataType()); - config::loadFromFD(fd, *data); - return data; - }; - - signalCall.signal = [handler](const FileDescriptor peerFD, std::shared_ptr& data) { - std::shared_ptr tmpData = std::static_pointer_cast(data); - handler(peerFD, tmpData); - }; - - mSignalsCallbacks[methodID] = std::make_shared(std::move(signalCall)); + setSignalHandlerInternal(methodID, handler); // Broadcast the new signal: std::vector ids {methodID}; - data = std::make_shared(ids); + data = std::make_shared(ids); for (const auto kv : mSockets) { peerFDs.push_back(kv.first); @@ -514,10 +551,9 @@ void Processor::setSignalHandler(const MethodID methodID, } for (const auto peerFD : peerFDs) { - callSync(REGISTER_SIGNAL_METHOD_ID, - peerFD, - data, - DEFAULT_METHOD_TIMEOUT); + signalInternal(REGISTER_SIGNAL_METHOD_ID, + peerFD, + data); } } @@ -530,7 +566,7 @@ MessageID Processor::callAsync(const MethodID methodID, { Lock lock(mStateMutex); auto request = MethodRequest::create(methodID, peerFD, data, process); - mRequestQueue.push(Event::METHOD, request); + mRequestQueue.pushBack(Event::METHOD, request); return request->messageID; } @@ -541,16 +577,14 @@ std::shared_ptr Processor::callSync(const MethodID methodID, const std::shared_ptr& data, unsigned int timeoutMS) { - std::shared_ptr result; + Result result; std::mutex mutex; std::condition_variable cv; - Status returnStatus = ipc::Status::UNDEFINED; - auto process = [&result, &mutex, &cv, &returnStatus](Status status, std::shared_ptr returnedData) { + auto process = [&result, &mutex, &cv](const Result && r) { std::unique_lock lock(mutex); - returnStatus = status; - result = returnedData; + result = std::move(r); cv.notify_all(); }; @@ -559,8 +593,8 @@ std::shared_ptr Processor::callSync(const MethodID methodID, data, process); - auto isResultInitialized = [&returnStatus]() { - return returnStatus != ipc::Status::UNDEFINED; + auto isResultInitialized = [&result]() { + return result.isValid(); }; std::unique_lock lock(mutex); @@ -594,9 +628,17 @@ std::shared_ptr Processor::callSync(const MethodID methodID, } } - throwOnError(returnStatus); + return result.get(); +} - return result; +template +void Processor::signalInternal(const MethodID methodID, + const FileDescriptor peerFD, + const std::shared_ptr& data) +{ + Lock lock(mStateMutex); + auto request = SignalRequest::create(methodID, peerFD, data); + mRequestQueue.pushFront(Event::SIGNAL, request); } template @@ -611,7 +653,7 @@ void Processor::signal(const MethodID methodID, } for (const FileDescriptor peerFD : it->second) { auto request = SignalRequest::create(methodID, peerFD, data); - mRequestQueue.push(Event::SIGNAL, request); + mRequestQueue.pushBack(Event::SIGNAL, request); } } diff --git a/common/ipc/internals/request-queue.hpp b/common/ipc/internals/request-queue.hpp index 82ba606..f648345 100644 --- a/common/ipc/internals/request-queue.hpp +++ b/common/ipc/internals/request-queue.hpp @@ -78,13 +78,22 @@ public: bool isEmpty() const; /** - * Push data to the queue + * Push data to back of the queue * * @param requestID request type * @param data data corresponding to the request */ - void push(const RequestIdType requestID, - const std::shared_ptr& data = nullptr); + void pushBack(const RequestIdType requestID, + const std::shared_ptr& data = nullptr); + + /** + * Push data to back of the queue + * + * @param requestID request type + * @param data data corresponding to the request + */ + void pushFront(const RequestIdType requestID, + const std::shared_ptr& data = nullptr); /** * @return get the data from the next request @@ -118,8 +127,8 @@ bool RequestQueue::isEmpty() const } template -void RequestQueue::push(const RequestIdType requestID, - const std::shared_ptr& data) +void RequestQueue::pushBack(const RequestIdType requestID, + const std::shared_ptr& data) { Request request(requestID, data); mRequests.push_back(std::move(request)); @@ -127,6 +136,15 @@ void RequestQueue::push(const RequestIdType requestID, } template +void RequestQueue::pushFront(const RequestIdType requestID, + const std::shared_ptr& data) +{ + Request request(requestID, data); + mRequests.push_front(std::move(request)); + mEventFD.send(); +} + +template typename RequestQueue::Request RequestQueue::pop() { mEventFD.receive(); diff --git a/common/ipc/internals/result-builder.hpp b/common/ipc/internals/result-builder.hpp new file mode 100644 index 0000000..3fe3c49 --- /dev/null +++ b/common/ipc/internals/result-builder.hpp @@ -0,0 +1,78 @@ +/* +* Copyright (c) 2015 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 storing result of a method - data or exception + */ + +#ifndef COMMON_IPC_RESULT_BUILDER_HPP +#define COMMON_IPC_RESULT_BUILDER_HPP + +#include "ipc/result.hpp" +#include +#include +#include + +namespace vasum { +namespace ipc { + +class ResultBuilder { +public: + ResultBuilder() + : mData(nullptr), + mExceptionPtr(nullptr) + {} + + ResultBuilder(const std::exception_ptr& exceptionPtr) + : mData(nullptr), + mExceptionPtr(exceptionPtr) + {} + + ResultBuilder(const std::shared_ptr& data) + : mData(data), + mExceptionPtr(nullptr) + + {} + + template + Result build() + { + return Result(std::move(std::static_pointer_cast(mData)), + std::move(mExceptionPtr)); + } + +private: + std::shared_ptr mData; + std::exception_ptr mExceptionPtr; +}; + +typedef std::function ResultBuilderHandler; + + +} // namespace ipc +} // namespace vasum + +#endif // COMMON_IPC_RESULT_BUILDER_HPP + + + + + + diff --git a/common/ipc/result.hpp b/common/ipc/result.hpp new file mode 100644 index 0000000..0edf172 --- /dev/null +++ b/common/ipc/result.hpp @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2015 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 storing result of a method - data or exception + */ + +#ifndef COMMON_IPC_RESULT_HPP +#define COMMON_IPC_RESULT_HPP + +#include +#include +#include + +namespace vasum { +namespace ipc { + +template +class Result { +public: + Result() + : mData(nullptr), + mExceptionPtr(nullptr) + {} + + Result(std::shared_ptr&& data, std::exception_ptr&& exceptionPtr) + : mData(std::move(data)), + mExceptionPtr(std::move(exceptionPtr)) + {} + + std::shared_ptr get() const + { + if (mExceptionPtr) { + std::rethrow_exception(mExceptionPtr); + } + return mData; + } + + bool isValid() const + { + return (bool)mExceptionPtr || (bool)mData; + } + +private: + std::shared_ptr mData; + std::exception_ptr mExceptionPtr; +}; + +template +struct ResultHandler { + typedef std::function < void(Result&&) > type; +}; + +} // namespace ipc +} // namespace vasum + +#endif // COMMON_IPC_RESULT_HPP diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 34b73fd..383c71d 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -29,6 +29,7 @@ #include "ipc/internals/acceptor.hpp" #include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" +#include "ipc/result.hpp" #include "logger/logger.hpp" #include diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp index 5d7dab6..a73a612 100644 --- a/common/ipc/types.cpp +++ b/common/ipc/types.cpp @@ -41,40 +41,7 @@ MessageID getNextMessageID() return ++gLastMessageID; } -std::string toString(const Status status) -{ - switch (status) { - case Status::OK: return "No error, everything is OK"; - case Status::PARSING_ERROR: return "Exception during reading/parsing data from the socket"; - case Status::SERIALIZATION_ERROR: return "Exception during writing/serializing data to the socket"; - case Status::PEER_DISCONNECTED: return "No such peer. Might got disconnected."; - case Status::NAUGHTY_PEER: return "Peer performed a forbidden action."; - case Status::REMOVED_PEER: return "Removing peer"; - case Status::CLOSING: return "Closing IPC"; - case Status::UNDEFINED: return "Undefined state"; - default: return "Unknown status"; - } -} -void throwOnError(const Status status) -{ - if (status == Status::OK) { - return; - } - std::string message = toString(status); - LOGE(message); - - switch (status) { - case Status::PARSING_ERROR: throw IPCParsingException(message); - case Status::SERIALIZATION_ERROR: throw IPCSerializationException(message); - case Status::PEER_DISCONNECTED: throw IPCPeerDisconnectedException(message); - case Status::NAUGHTY_PEER: throw IPCNaughtyPeerException(message); - case Status::REMOVED_PEER: throw IPCException(message); - case Status::CLOSING: throw IPCException(message); - case Status::UNDEFINED: throw IPCException(message); - default: return throw IPCException(message); - } -} } // namespace ipc } // namespace vasum diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index 6186f65..b5411b3 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -42,22 +42,8 @@ typedef std::function PeerCallback; typedef std::function& data)> SerializeCallback; typedef std::function(int fd)> ParseCallback; -enum class Status : int { - OK = 0, - PARSING_ERROR, - SERIALIZATION_ERROR, - PEER_DISCONNECTED, - NAUGHTY_PEER, - REMOVED_PEER, - CLOSING, - UNDEFINED -}; - -std::string toString(const Status status); -void throwOnError(const Status status); MessageID getNextMessageID(); - template struct MethodHandler { typedef std::function(FileDescriptor peerFD, @@ -70,12 +56,6 @@ struct SignalHandler { std::shared_ptr& data)> type; }; -template -struct ResultHandler { - typedef std::function& resultData)> type; -}; - } // namespace ipc } // namespace vasum diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index e5609f7..5408735 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -33,6 +33,7 @@ #include "ipc/service.hpp" #include "ipc/client.hpp" #include "ipc/types.hpp" +#include "ipc/result.hpp" #include "utils/glib-loop.hpp" #include "utils/latch.hpp" #include "utils/value-latch.hpp" @@ -353,10 +354,8 @@ BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho) c.start(); //Async call - auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { - if (status == ipc::Status::OK) { - recvDataLatch.set(data); - } + auto dataBack = [&recvDataLatch](Result && r) { + recvDataLatch.set(r.get()); }; c.callAsync(1, sentData, dataBack); @@ -376,10 +375,8 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) FileDescriptor peerFD = connect(s, c); // Async call - auto dataBack = [&recvDataLatch](ipc::Status status, std::shared_ptr& data) { - if (status == ipc::Status::OK) { - recvDataLatch.set(data); - } + auto dataBack = [&recvDataLatch](Result && r) { + recvDataLatch.set(r.get()); }; s.callAsync(1, peerFD, sentData, dataBack); @@ -431,7 +428,7 @@ BOOST_AUTO_TEST_CASE(ParseError) BOOST_AUTO_TEST_CASE(DisconnectedPeerError) { - ValueLatch retStatusLatch; + ValueLatch> retStatusLatch; Service s(socketPath); auto method = [](const FileDescriptor, std::shared_ptr&) { @@ -445,20 +442,20 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) Client c(socketPath); c.start(); - auto dataBack = [&retStatusLatch](ipc::Status status, std::shared_ptr&) { - retStatusLatch.set(status); + auto dataBack = [&retStatusLatch](Result && r) { + retStatusLatch.set(std::move(r)); }; std::shared_ptr sentData(new SendData(78)); c.callAsync(1, sentData, dataBack); // Wait for the response - ipc::Status retStatus = retStatusLatch.get(TIMEOUT); + Result result = retStatusLatch.get(TIMEOUT); // The disconnection might have happened: // - after sending the message (PEER_DISCONNECTED) // - during external serialization (SERIALIZATION_ERROR) - BOOST_CHECK(retStatus == ipc::Status::PEER_DISCONNECTED || retStatus == ipc::Status::SERIALIZATION_ERROR); + BOOST_CHECK_THROW(result.get(), IPCException); } @@ -627,6 +624,32 @@ BOOST_AUTO_TEST_CASE(ClientGSource) BOOST_CHECK(l.wait(TIMEOUT)); } +BOOST_AUTO_TEST_CASE(UsersError) +{ + const int TEST_ERROR_CODE = -234; + const std::string TEST_ERROR_MESSAGE = "Ay, caramba!"; + + Service s(socketPath); + Client c(socketPath); + auto clientID = connect(s, c); + + auto throwingMethodHandler = [&](const FileDescriptor, std::shared_ptr&) -> std::shared_ptr { + throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); + }; + + s.setMethodHandler(1, throwingMethodHandler); + c.setMethodHandler(1, throwingMethodHandler); + + std::shared_ptr sentData(new SendData(78)); + + auto hasProperData = [&](const IPCUserException & e) { + return e.getCode() == TEST_ERROR_CODE && e.what() == TEST_ERROR_MESSAGE; + }; + + BOOST_CHECK_EXCEPTION((c.callSync(1, sentData, TIMEOUT)), IPCUserException, hasProperData); + BOOST_CHECK_EXCEPTION((s.callSync(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData); + +} // BOOST_AUTO_TEST_CASE(ConnectionLimitTest) // { // unsigned oldLimit = ipc::getMaxFDNumber(); -- 2.7.4 From a03c3847ce96b3854f9506ff041d7d2545617f63 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 29 Jan 2015 10:11:47 +0100 Subject: [PATCH 10/16] Preserve zones order. Fix switching zone to the next one. [Bug/Feature] An order of zones was not preserved. [Cause] N/A [Solution] N/A [Verification] Run tests Change-Id: I4cf9b235620bd0cf2b5e3de386ddfe6ba8a54813 --- server/zone.hpp | 5 +- server/zones-manager.cpp | 362 +++++++++++++++------------ server/zones-manager.hpp | 19 +- tests/unit_tests/server/ut-zones-manager.cpp | 4 +- 4 files changed, 223 insertions(+), 167 deletions(-) diff --git a/server/zone.hpp b/server/zone.hpp index 8cd3535..6105209 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -58,8 +58,9 @@ public: const std::string& dbPath, const std::string& lxcTemplatePrefix, const std::string& baseRunMountPointPath); - Zone(Zone&&) = default; - virtual ~Zone(); + Zone(const Zone&) = delete; + Zone& operator=(const Zone&) = delete; + ~Zone(); typedef ZoneConnection::NotifyActiveZoneCallback NotifyActiveZoneCallback; typedef ZoneConnection::DisplayOffCallback DisplayOffCallback; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index fa6ec80..a31a0f3 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -87,6 +87,53 @@ void remove(std::vector& v, const T& item) v.erase(std::remove(v.begin(), v.end(), item), v.end()); } +template +Iter circularFindNext(Iter begin, Iter end, Iter current, Predicate pred) +{ + if (begin == end || current == end) { + return end; + } + for (Iter next = current;;) { + ++ next; + if (next == end) { + next = begin; + } + if (next == current) { + return end; + } + if (pred(*next)) { + return next; + } + } +} + +std::vector>::iterator find(std::vector>& zones, + const std::string& id) +{ + auto equalId = [&id](const std::unique_ptr& zone) { + return zone->getId() == id; + }; + return std::find_if(zones.begin(), zones.end(), equalId); +} + +Zone& get(std::vector>::iterator iter) +{ + return **iter; +} + +Zone& at(std::vector>& zones, const std::string& id) +{ + auto iter = find(zones, id); + if (iter == zones.end()) { + throw std::out_of_range("id not found"); + } + return get(iter); +} + +bool zoneIsRunning(const std::unique_ptr& zone) { + return zone->isRunning(); +} + } // namespace ZonesManager::ZonesManager(const std::string& configPath) @@ -200,7 +247,7 @@ void ZonesManager::updateDefaultId() LOGT("Keep empty defaultId"); return; } - if (mZones.find(mDynamicConfig.defaultId) != mZones.end()) { + if (find(mZones, mDynamicConfig.defaultId) != mZones.end()) { LOGT("Keep " << mDynamicConfig.defaultId << " as defaultId"); return; } @@ -210,7 +257,7 @@ void ZonesManager::updateDefaultId() mDynamicConfig.defaultId.clear(); LOGD("DefaultId cleared"); } else { - mDynamicConfig.defaultId = mZones.begin()->first; + mDynamicConfig.defaultId = mZones.front()->getId(); LOGD("DefaultId changed to " << mDynamicConfig.defaultId); } saveDynamicConfig(); @@ -248,7 +295,10 @@ void ZonesManager::createZone(const std::string& zoneConfigPath) Lock lock(mMutex); - mZones.insert(ZoneMap::value_type(id, std::move(zone))); + if (find(mZones, id) != mZones.end()) { + throw ZoneOperationException("Zone already exists"); + } + mZones.push_back(std::move(zone)); // after zone is created successfully, put a file informing that zones are enabled if (mZones.size() == 1) { @@ -263,14 +313,14 @@ void ZonesManager::destroyZone(const std::string& zoneId) { Lock lock(mMutex); - auto it = mZones.find(zoneId); - if (it == mZones.end()) { + auto iter = find(mZones, zoneId); + if (iter == mZones.end()) { LOGE("Failed to destroy zone " << zoneId << ": no such zone"); throw ZoneOperationException("No such zone"); } - it->second->setDestroyOnExit(); - mZones.erase(it); + get(iter).setDestroyOnExit(); + mZones.erase(iter); if (mZones.empty()) { if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME))) { @@ -289,39 +339,51 @@ void ZonesManager::destroyZone(const std::string& zoneId) void ZonesManager::focus(const std::string& zoneId) { Lock lock(mMutex); + auto iter = find(mZones, zoneId); + focusInternal(iter); +} - if (zoneId == mActiveZoneId) { - // nothing to do +void ZonesManager::focusInternal(Zones::iterator iter) +{ + // assume mutex is locked + if (iter == mZones.end()) { + if (!mActiveZoneId.empty()) { + LOGI("Focus to: host"); + // give back the focus to the host + // TODO switch to host vt + mActiveZoneId.clear(); + } return; } - if (zoneId.empty()) { - LOGI("Focus to: host"); - // give back the focus to the host - // TODO switch to host vt - mActiveZoneId.clear(); + Zone& zone = get(iter); + std::string zoneId = zone.getId(); + + if (zoneId == mActiveZoneId) { return; } - LOGI("Focus to: " << zoneId); - - /* try to access the object first to throw immediately if it doesn't exist */ - auto& foregroundZone = mZones.at(zoneId); + if (!zone.isRunning()) { + LOGE("Can't focus not running zone " << zoneId); + assert(false); + return; + } - assert(foregroundZone->isRunning()); + LOGI("Focus to: " << zone.getId()); - if (!foregroundZone->activateVT()) { - LOGE("Failed to activate zones VT. Aborting focus."); + if (!zone.activateVT()) { + LOGE("Failed to activate zones VT"); return; } for (auto& zone : mZones) { - if (zone.first == zoneId) { - LOGD(zone.first << ": being sent to foreground"); - zone.second->goForeground(); + std::string id = zone->getId(); + if (id == zoneId) { + LOGD(id << ": being sent to foreground"); + zone->goForeground(); } else { - LOGD(zone.first << ": being sent to background"); - zone.second->goBackground(); + LOGD(id << ": being sent to background"); + zone->goBackground(); } } mActiveZoneId = zoneId; @@ -329,29 +391,26 @@ void ZonesManager::focus(const std::string& zoneId) void ZonesManager::refocus() { - Lock lock(mMutex); + // assume mutex is locked // check if refocus is required - auto oldIter = mZones.find(mActiveZoneId); - if (oldIter != mZones.end() && oldIter->second->isRunning()) { + auto oldIter = find(mZones, mActiveZoneId); + if (oldIter != mZones.end() && get(oldIter).isRunning()) { return; } // try to refocus to defaultId - auto iter = mZones.find(mDynamicConfig.defaultId); - if (iter != mZones.end() && iter->second->isRunning()) { + auto iter = find(mZones, mDynamicConfig.defaultId); + if (iter != mZones.end() && get(iter).isRunning()) { // focus to default - focus(iter->first); + focusInternal(iter); } else { // focus to any running or to host if not found - auto zoneIsRunning = [](const ZoneMap::value_type& pair) { - return pair.second->isRunning(); - }; auto iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); if (iter == mZones.end()) { - focus(std::string()); + focusInternal(mZones.end()); } else { - focus(iter->first); + focusInternal(iter); } } } @@ -363,7 +422,7 @@ void ZonesManager::startAll() Lock lock(mMutex); for (auto& zone : mZones) { - zone.second->start(); + zone->start(); } refocus(); @@ -376,7 +435,7 @@ void ZonesManager::stopAll() Lock lock(mMutex); for (auto& zone : mZones) { - zone.second->stop(); + zone->stop(); } refocus(); @@ -386,70 +445,81 @@ bool ZonesManager::isPaused(const std::string& zoneId) { Lock lock(mMutex); - auto iter = mZones.find(zoneId); + auto iter = find(mZones, zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); throw ZoneOperationException("No such zone"); } - return iter->second->isPaused(); + return get(iter).isPaused(); } bool ZonesManager::isRunning(const std::string& zoneId) { Lock lock(mMutex); - auto iter = mZones.find(zoneId); + auto iter = find(mZones, zoneId); if (iter == mZones.end()) { LOGE("No such zone id: " << zoneId); throw ZoneOperationException("No such zone"); } - return iter->second->isRunning(); + return get(iter).isRunning(); } -std::string ZonesManager::getRunningForegroundZoneId() const +std::string ZonesManager::getRunningForegroundZoneId() { Lock lock(mMutex); + auto iter = getRunningForegroundZoneIterator(); + return iter == mZones.end() ? std::string() : get(iter).getId(); +} - if (!mActiveZoneId.empty() && !mZones.at(mActiveZoneId)->isRunning()) { +std::string ZonesManager::getNextToForegroundZoneId() +{ + Lock lock(mMutex); + auto iter = getNextToForegroundZoneIterator(); + return iter == mZones.end() ? std::string() : get(iter).getId(); +} + +ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator() +{ + // assume mutex is locked + if (mActiveZoneId.empty()) { + return mZones.end(); + } + auto iter = find(mZones, mActiveZoneId); + if (!get(iter).isRunning()) { // Can zone change its state by itself? // Maybe when it is shut down by itself? TODO check it LOGW("Active zone " << mActiveZoneId << " is not running any more!"); assert(false); - return std::string(); + return mZones.end(); } - - return mActiveZoneId; + return iter; } -std::string ZonesManager::getNextToForegroundZoneId() +ZonesManager::Zones::iterator ZonesManager::getNextToForegroundZoneIterator() { - Lock lock(mMutex); - - // handles case where there is no next zone - if (mZones.size() < 2) { - return std::string(); - } - - for (auto it = mZones.begin(); it != mZones.end(); ++it) { - if (it->first == mActiveZoneId && it->second->isRunning()) { - auto nextIt = std::next(it); - if (nextIt != mZones.end()) { - return nextIt->first; - } - } + // assume mutex is locked + auto current = find(mZones, mActiveZoneId); + if (current == mZones.end()) { + // find any running + return std::find_if(mZones.begin(), mZones.end(), zoneIsRunning); + } else { + // find next running + return circularFindNext(mZones.begin(), mZones.end(), current, zoneIsRunning); } - return mZones.begin()->first;//TODO fix - check isRunning } void ZonesManager::switchingSequenceMonitorNotify() { LOGI("switchingSequenceMonitorNotify() called"); - std::string nextZoneId = getNextToForegroundZoneId(); + Lock lock(mMutex); - if (!nextZoneId.empty()) { - focus(nextZoneId); + auto next = getNextToForegroundZoneIterator(); + + if (next != mZones.end()) { + focusInternal(next); } } @@ -461,7 +531,7 @@ void ZonesManager::setZonesDetachOnExit() mDetachOnExit = true; for (auto& zone : mZones) { - zone.second->setDetachOnExit(); + zone->setDetachOnExit(); } } @@ -475,9 +545,9 @@ void ZonesManager::notifyActiveZoneHandler(const std::string& caller, Lock lock(mMutex); try { - const std::string activeZone = getRunningForegroundZoneId(); - if (!activeZone.empty() && caller != activeZone) { - mZones[activeZone]->sendNotification(caller, application, message); + auto iter = getRunningForegroundZoneIterator(); + if (iter != mZones.end() && caller != get(iter).getId()) { + get(iter).sendNotification(caller, application, message); } } catch(const VasumException&) { LOGE("Notification from " << caller << " hasn't been sent"); @@ -489,15 +559,16 @@ void ZonesManager::displayOffHandler(const std::string& /*caller*/) // get config of currently set zone and switch if switchToDefaultAfterTimeout is true Lock lock(mMutex); - auto activeZone = mZones.find(mActiveZoneId); + auto activeIter = find(mZones, mActiveZoneId); + auto defaultIter = find(mZones, mDynamicConfig.defaultId); - if (activeZone != mZones.end() && - activeZone->second->isSwitchToDefaultAfterTimeoutAllowed() && - !mDynamicConfig.defaultId.empty() && - mZones.at(mDynamicConfig.defaultId)->isRunning()) { + if (activeIter != mZones.end() && + defaultIter != mZones.end() && + get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() && + get(defaultIter).isRunning()) { LOGI("Switching to default zone " << mDynamicConfig.defaultId); - focus(mDynamicConfig.defaultId); + focusInternal(defaultIter); } } @@ -532,20 +603,20 @@ void ZonesManager::handleZoneMoveFileRequest(const std::string& srcZoneId, Lock lock(mMutex); - ZoneMap::const_iterator srcIter = mZones.find(srcZoneId); + auto srcIter = find(mZones, srcZoneId); if (srcIter == mZones.end()) { LOGE("Source zone '" << srcZoneId << "' not found"); return; } - Zone& srcZone = *srcIter->second; + Zone& srcZone = get(srcIter); - ZoneMap::const_iterator dstIter = mZones.find(dstZoneId); + auto dstIter = find(mZones, dstZoneId); if (dstIter == mZones.end()) { LOGE("Destination zone '" << dstZoneId << "' not found"); result->set(g_variant_new("(s)", api::zone::FILE_MOVE_DESTINATION_NOT_FOUND.c_str())); return; } - Zone& dstContanier = *dstIter->second; + Zone& dstContanier = get(dstIter); if (srcZoneId == dstZoneId) { LOGE("Cannot send a file to yourself"); @@ -627,14 +698,14 @@ void ZonesManager::handleProxyCall(const std::string& caller, Lock lock(mMutex); - ZoneMap::const_iterator targetIter = mZones.find(target); + auto targetIter = find(mZones, target); if (targetIter == mZones.end()) { LOGE("Target zone '" << target << "' not found"); result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target"); return; } - Zone& targetZone = *targetIter->second; + Zone& targetZone = get(targetIter); targetZone.proxyCallAsync(targetBusName, targetObjectPath, targetInterface, @@ -643,14 +714,14 @@ void ZonesManager::handleProxyCall(const std::string& caller, asyncResultCallback); } -void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const +void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) { Lock lock(mMutex); std::vector entries; for (auto& zone : mZones) { - GVariant* zoneId = g_variant_new_string(zone.first.c_str()); - GVariant* dbusAddress = g_variant_new_string(zone.second->getDbusAddress().c_str()); + GVariant* zoneId = g_variant_new_string(zone->getId().c_str()); + GVariant* dbusAddress = g_variant_new_string(zone->getDbusAddress().c_str()); GVariant* entry = g_variant_new_dict_entry(zoneId, dbusAddress); entries.push_back(entry); } @@ -664,13 +735,13 @@ void ZonesManager::handleDbusStateChanged(const std::string& zoneId, mHostConnection.signalZoneDbusState(zoneId, dbusAddress); } -void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const +void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) { Lock lock(mMutex); std::vector zoneIds; for(auto& zone: mZones){ - zoneIds.push_back(g_variant_new_string(zone.first.c_str())); + zoneIds.push_back(g_variant_new_string(zone->getId().c_str())); } GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"), @@ -683,10 +754,7 @@ void ZonesManager::handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer { LOGI("GetActiveZoneId call"); - Lock lock(mMutex); - std::string id = getRunningForegroundZoneId(); - result->set(g_variant_new("(s)", id.c_str())); } @@ -697,19 +765,20 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, Lock lock(mMutex); - if (mZones.count(id) == 0) { + auto iter = find(mZones, id); + if (iter == mZones.end()) { LOGE("No zone with id=" << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - const auto& zone = mZones[id]; + Zone& zone = get(iter); const char* state; - if (zone->isRunning()) { + if (zone.isRunning()) { state = "RUNNING"; - } else if (zone->isStopped()) { + } else if (zone.isStopped()) { state = "STOPPED"; - } else if (zone->isPaused()) { + } else if (zone.isPaused()) { state = "FROZEN"; } else { LOGE("Unrecognized state of zone id=" << id); @@ -719,9 +788,9 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id, result->set(g_variant_new("((siss))", id.c_str(), - zone->getVT(), + zone.getVT(), state, - zone->getRootPath().c_str())); + zone.getRootPath().c_str())); } void ZonesManager::handleDeclareFileCall(const std::string& zone, @@ -736,7 +805,7 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone, try { Lock lock(mMutex); - mZones.at(zone)->declareFile(type, path, flags, mode); + at(mZones, zone).declareFile(type, path, flags, mode); result->setVoid(); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -760,7 +829,7 @@ void ZonesManager::handleDeclareMountCall(const std::string& source, try { Lock lock(mMutex); - mZones.at(zone)->declareMount(source, target, type, flags, data); + at(mZones, zone).declareMount(source, target, type, flags, data); result->setVoid(); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -780,7 +849,7 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source, try { Lock lock(mMutex); - mZones.at(zone)->declareLink(source, target); + at(mZones, zone).declareLink(source, target); result->setVoid(); } catch (const std::out_of_range&) { LOGE("No zone with id=" << zone); @@ -798,21 +867,21 @@ void ZonesManager::handleSetActiveZoneCall(const std::string& id, Lock lock(mMutex); - auto zone = mZones.find(id); - if (zone == mZones.end()){ + auto iter = find(mZones, id); + if (iter == mZones.end()){ LOGE("No zone with id=" << id ); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - if (!zone->second->isRunning()){ + if (!get(iter).isRunning()){ LOGE("Could not activate stopped or paused zone"); result->setError(api::host::ERROR_ZONE_NOT_RUNNING, "Could not activate stopped or paused zone"); return; } - focus(id); + focusInternal(iter); result->setVoid(); } @@ -885,7 +954,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, namespace fs = boost::filesystem; // check if zone does not exist - if (mZones.find(id) != mZones.end()) { + if (find(mZones, id) != mZones.end()) { LOGE("Cannot create " << id << " zone - already exists!"); result->setError(api::ERROR_INVALID_ID, "Already exists"); return; @@ -952,19 +1021,14 @@ void ZonesManager::handleCreateZoneCall(const std::string& id, void ZonesManager::handleDestroyZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result) { - Lock lock(mMutex); - - if (mZones.find(id) == mZones.end()) { - LOGE("Failed to destroy zone - no such zone id: " << id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } - - LOGI("Destroying zone " << id); - auto destroyer = [id, result, this] { try { + LOGI("Destroying zone " << id); + destroyZone(id); + } catch (const ZoneOperationException& e) { + LOGE("Failed to destroy zone - no such zone id: " << id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); } catch (const VasumException& e) { LOGE("Error during zone destruction: " << e.what()); result->setError(api::ERROR_INTERNAL, "Failed to destroy zone"); @@ -981,24 +1045,18 @@ void ZonesManager::handleShutdownZoneCall(const std::string& id, { LOGI("ShutdownZone call; Id=" << id ); - Lock lock(mMutex); - - if (mZones.find(id) == mZones.end()) { - LOGE("Failed to shutdown zone - no such zone id: " << id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } - - LOGT("Shutdown zone " << id); - auto shutdown = [id, result, this] { try { - ZoneMap::mapped_type zone; - { - Lock lock(mMutex); - zone = mZones.at(id); + LOGT("Shutdown zone " << id); + + Lock lock(mMutex); + auto iter = find(mZones, id); + if (iter == mZones.end()) { + LOGE("Failed to shutdown zone - no such zone id: " << id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; } - zone->stop(); + get(iter).stop(); refocus(); result->setVoid(); } catch (ZoneOperationException& e) { @@ -1016,25 +1074,19 @@ void ZonesManager::handleStartZoneCall(const std::string& id, { LOGI("StartZone call; Id=" << id ); - Lock lock(mMutex); - - if (mZones.find(id) == mZones.end()) { - LOGE("Failed to start zone - no such zone id: " << id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } - - LOGT("Start zone " << id); - auto startAsync = [this, id, result]() { try { - ZoneMap::mapped_type zone; - { - Lock lock(mMutex); - zone = mZones.at(id); + LOGT("Start zone " << id ); + + Lock lock(mMutex); + auto iter = find(mZones, id); + if (iter == mZones.end()) { + LOGE("Failed to start zone - no such zone id: " << id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; } - zone->start(); - focus(id); + get(iter).start(); + focusInternal(iter); result->setVoid(); } catch (const std::exception& e) { LOGE(id << ": failed to start: " << e.what()); @@ -1051,14 +1103,14 @@ void ZonesManager::handleLockZoneCall(const std::string& id, Lock lock(mMutex); - auto iter = mZones.find(id); + auto iter = find(mZones, id); if (iter == mZones.end()) { LOGE("Failed to lock zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - auto& zone = *iter->second; + Zone& zone = get(iter); if (!zone.isRunning()) { LOGE("Zone id=" << id << " is not running."); result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); @@ -1085,14 +1137,14 @@ void ZonesManager::handleUnlockZoneCall(const std::string& id, Lock lock(mMutex); - auto iter = mZones.find(id); + auto iter = find(mZones, id); if (iter == mZones.end()) { LOGE("Failed to unlock zone - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - auto& zone = *iter->second; + Zone& zone = get(iter); if (!zone.isPaused()) { LOGE("Zone id=" << id << " is not paused."); result->setError(api::ERROR_INVALID_STATE, "Zone is not paused"); @@ -1120,14 +1172,14 @@ void ZonesManager::handleGrantDeviceCall(const std::string& id, Lock lock(mMutex); - auto iter = mZones.find(id); + auto iter = find(mZones, id); if (iter == mZones.end()) { LOGE("Failed to grant device - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - auto& zone = *iter->second; + Zone& zone = get(iter); if (!zone.isRunning() && !zone.isPaused()) { LOGE("Zone id=" << id << " is not running"); result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); @@ -1160,14 +1212,14 @@ void ZonesManager::handleRevokeDeviceCall(const std::string& id, Lock lock(mMutex); - auto iter = mZones.find(id); + auto iter = find(mZones, id); if (iter == mZones.end()) { LOGE("Failed to revoke device - no such zone id: " << id); result->setError(api::ERROR_INVALID_ID, "No such zone id"); return; } - auto& zone = *iter->second; + Zone& zone = get(iter); if (!zone.isRunning() && !zone.isPaused()) { LOGE("Zone id=" << id << " is not running"); result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 72dd952..b46768f 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -34,7 +34,6 @@ #include "utils/worker.hpp" #include -#include #include @@ -92,7 +91,7 @@ public: /** * @return id of the currently focused/foreground zone */ - std::string getRunningForegroundZoneId() const; + std::string getRunningForegroundZoneId(); /** * @return id of next to currently focused/foreground zone. If currently focused zone @@ -110,18 +109,24 @@ private: typedef std::unique_lock Lock; utils::Worker::Pointer mWorker; - mutable Mutex mMutex; // used to protect mZones + Mutex mMutex; // used to protect mZones ZonesManagerConfig mConfig; //TODO make it const ZonesManagerDynamicConfig mDynamicConfig; HostConnection mHostConnection; // to hold InputMonitor pointer to monitor if zone switching sequence is recognized std::unique_ptr mSwitchingSequenceMonitor; std::unique_ptr mProxyCallPolicy; - typedef std::unordered_map> ZoneMap;//TODO should keep order of insertions - ZoneMap mZones; // map of zones, id is the key + // like set but keep insertion order + // smart pointer is needed because Zone is not moveable (because of mutex) + typedef std::vector> Zones; + Zones mZones; std::string mActiveZoneId; bool mDetachOnExit; + Zones::iterator getRunningForegroundZoneIterator(); + Zones::iterator getNextToForegroundZoneIterator(); + void focusInternal(Zones::iterator iter); + void saveDynamicConfig(); void updateDefaultId(); void refocus(); @@ -146,9 +151,9 @@ private: const std::string& targetMethod, GVariant* parameters, dbus::MethodResultBuilder::Pointer result); - void handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const; + void handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result); void handleDbusStateChanged(const std::string& zoneId, const std::string& dbusAddress); - void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const; + void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result); void handleGetZoneInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); void handleDeclareFileCall(const std::string& zone, diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 3929c77..65f0f2b 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -962,9 +962,7 @@ BOOST_AUTO_TEST_CASE(GetZoneIdsTest) "ut-zones-manager-console3-dbus"}; std::vector returnedIds = dbus.callMethodGetZoneIds(); - BOOST_CHECK(std::is_permutation(returnedIds.begin(), - returnedIds.end(), - zoneIds.begin())); + BOOST_CHECK(returnedIds == zoneIds);// order should be preserved } BOOST_AUTO_TEST_CASE(GetActiveZoneIdTest) -- 2.7.4 From 5bb8b83c9250a15c40eec4274af01da74d877057 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Fri, 30 Jan 2015 14:08:09 +0100 Subject: [PATCH 11/16] Fix use of uninitialized variable in ut [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Run tests under valgrind Change-Id: Ibe0f6d7da3a8592abd660b66f252ae0bf2fbf896 --- tests/unit_tests/config/testconfig-example.hpp | 14 ++++++++++++++ tests/unit_tests/config/ut-configuration.cpp | 5 +---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/config/testconfig-example.hpp b/tests/unit_tests/config/testconfig-example.hpp index c8563d0..c05b63c 100644 --- a/tests/unit_tests/config/testconfig-example.hpp +++ b/tests/unit_tests/config/testconfig-example.hpp @@ -160,4 +160,18 @@ const std::string jsonTestString = "{ \"type\": \"SubConfig\", \"value\": { \"intVal\": 54321, \"intVector\": [ 1 ], " "\"subSubObj\": { \"intVal\": 234 } } } ] }"; +const std::string jsonEmptyTestString = + "{ \"intVal\": 0, " + "\"int64Val\": 0, " + "\"stringVal\": \"\", " + "\"boolVal\": false, " + "\"emptyIntVector\": [ ], " + "\"intVector\": [ ], " + "\"stringVector\": [ ], " + "\"subObj\": { \"intVal\": 0, \"intVector\": [ ], \"subSubObj\": { \"intVal\": 0 } }, " + "\"subVector\": [ ], " + "\"union1\": { \"type\": \"int\", \"value\": 0 }, " + "\"union2\": { \"type\": \"int\", \"value\": 0 }, " + "\"unions\": [ ] }"; + #endif diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index e014f68..2e3b487 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -304,10 +304,7 @@ BOOST_AUTO_TEST_CASE(FromKVWithDefaultsTest) // all in db saveToKVStore(DB_PATH, config, DB_PREFIX); TestConfig outConfig2; - outConfig2.union1.set(0); - outConfig2.union2.set(0); - std::string emptyConfig = saveToJsonString(outConfig2); - loadFromKVStoreWithJson(DB_PATH, emptyConfig, outConfig2, DB_PREFIX); + loadFromKVStoreWithJson(DB_PATH, jsonEmptyTestString, outConfig2, DB_PREFIX); std::string out2 = saveToJsonString(outConfig2); BOOST_CHECK_EQUAL(out2, jsonTestString); -- 2.7.4 From 84d3cd04fd0718842bff9790950cbf54eb0671d6 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Fri, 30 Jan 2015 17:54:41 +0100 Subject: [PATCH 12/16] IPC: Changed recursive_mutex to mutex in the Processor [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: If683c017354c5a9f7fdf8bb5ce2ad84f9dd82fdd --- common/ipc/internals/finish-request.hpp | 4 +- common/ipc/internals/processor.cpp | 99 ++++++++++++---------------- common/ipc/internals/processor.hpp | 65 +++++++----------- common/ipc/internals/remove-peer-request.hpp | 4 +- 4 files changed, 69 insertions(+), 103 deletions(-) diff --git a/common/ipc/internals/finish-request.hpp b/common/ipc/internals/finish-request.hpp index 3fd4a4f..d09a14e 100644 --- a/common/ipc/internals/finish-request.hpp +++ b/common/ipc/internals/finish-request.hpp @@ -35,11 +35,11 @@ public: FinishRequest(const FinishRequest&) = delete; FinishRequest& operator=(const FinishRequest&) = delete; - FinishRequest(const std::shared_ptr& conditionPtr) + FinishRequest(const std::shared_ptr& conditionPtr) : conditionPtr(conditionPtr) {} - std::shared_ptr conditionPtr; + std::shared_ptr conditionPtr; }; } // namespace ipc diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 58beca8..1f51d5e 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -66,6 +66,7 @@ Processor::Processor(const std::string& logName, LOGS(mLogPrefix + "Processor Constructor"); utils::signalBlock(SIGPIPE); + using namespace std::placeholders; setSignalHandlerInternal(REGISTER_SIGNAL_METHOD_ID, std::bind(&Processor::onNewSignals, this, _1, _2)); @@ -94,7 +95,7 @@ void Processor::start(bool usesExternalPolling) LOGS(mLogPrefix + "Processor start"); Lock lock(mStateMutex); - if (!isStarted()) { + if (!mIsRunning) { LOGI(mLogPrefix + "Processor start"); mIsRunning = true; mUsesExternalPolling = usesExternalPolling; @@ -109,7 +110,7 @@ void Processor::stop() LOGS(mLogPrefix + "Processor stop"); if (isStarted()) { - auto conditionPtr = std::make_shared(); + auto conditionPtr = std::make_shared(); { Lock lock(mStateMutex); auto request = std::make_shared(conditionPtr); @@ -124,7 +125,7 @@ void Processor::stop() // Wait till the FINISH request is served Lock lock(mStateMutex); conditionPtr->wait(lock, [this]() { - return !isStarted(); + return !mIsRunning; }); } } @@ -168,31 +169,25 @@ FileDescriptor Processor::addPeer(const std::shared_ptr& socketPtr) return peerFD; } -void Processor::removePeer(const FileDescriptor peerFD) +void Processor::removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock) { LOGS(mLogPrefix + "Processor removePeer peerFD: " << peerFD); - { - Lock lock(mStateMutex); - mRequestQueue.removeIf([peerFD](Request & request) { - return request.requestID == Event::ADD_PEER && - request.get()->peerFD == peerFD; - }); - } - - // Remove peer and wait till he's gone - std::shared_ptr conditionPtr(new std::condition_variable_any()); - { - Lock lock(mStateMutex); - auto request = std::make_shared(peerFD, conditionPtr); - mRequestQueue.pushBack(Event::REMOVE_PEER, request); - } - auto isPeerDeleted = [&peerFD, this]()->bool { return mSockets.count(peerFD) == 0; }; - Lock lock(mStateMutex); + mRequestQueue.removeIf([peerFD](Request & request) { + return request.requestID == Event::ADD_PEER && + request.get()->peerFD == peerFD; + }); + + // Remove peer and wait till he's gone + std::shared_ptr conditionPtr(new std::condition_variable()); + + auto request = std::make_shared(peerFD, conditionPtr); + mRequestQueue.pushBack(Event::REMOVE_PEER, request); + conditionPtr->wait(lock, isPeerDeleted); } @@ -231,8 +226,6 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, const std::excep // Notify about the deletion mRemovedPeerCallback(peerFD); } - - resetPolling(); } void Processor::resetPolling() @@ -243,23 +236,20 @@ void Processor::resetPolling() return; } - { - Lock lock(mStateMutex); - LOGI(mLogPrefix + "Reseting mFDS.size: " << mSockets.size()); - // Setup polling on eventfd and sockets - mFDs.resize(mSockets.size() + 1); + LOGI(mLogPrefix + "Reseting mFDS.size: " << mSockets.size()); + // Setup polling on eventfd and sockets + mFDs.resize(mSockets.size() + 1); - mFDs[0].fd = mRequestQueue.getFD(); - mFDs[0].events = POLLIN; + mFDs[0].fd = mRequestQueue.getFD(); + mFDs[0].events = POLLIN; - auto socketIt = mSockets.begin(); - for (unsigned int i = 1; i < mFDs.size(); ++i) { - LOGI(mLogPrefix + "Reseting fd: " << socketIt->second->getFD()); - 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? - } + auto socketIt = mSockets.begin(); + for (unsigned int i = 1; i < mFDs.size(); ++i) { + LOGI(mLogPrefix + "Reseting fd: " << socketIt->second->getFD()); + 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? } } @@ -267,7 +257,10 @@ void Processor::run() { LOGS(mLogPrefix + "Processor run"); - resetPolling(); + { + Lock lock(mStateMutex); + resetPolling(); + } while (isStarted()) { LOGT(mLogPrefix + "Waiting for communication..."); @@ -284,12 +277,14 @@ void Processor::run() // Check for lost connections: if (handleLostConnections()) { // mFDs changed + resetPolling(); continue; } // Check for incoming data. if (handleInputs()) { // mFDs changed + resetPolling(); continue; } @@ -298,6 +293,7 @@ void Processor::run() mFDs[0].revents &= ~(POLLIN); if (handleEvent()) { // mFDs changed + resetPolling(); continue; } } @@ -335,7 +331,7 @@ bool Processor::handleLostConnection(const FileDescriptor peerFD) bool Processor::handleInputs() { - Lock lock(mStateMutex); + // Lock not needed, mFDs won't be changed by handleInput bool pollChanged = false; for (unsigned int i = 1; i < mFDs.size(); ++i) { @@ -351,6 +347,7 @@ bool Processor::handleInputs() bool Processor::handleInput(const FileDescriptor peerFD) { LOGS(mLogPrefix + "Processor handleInput peerFD: " << peerFD); + Lock lock(mStateMutex); std::shared_ptr socketPtr; @@ -384,7 +381,7 @@ bool Processor::handleInput(const FileDescriptor peerFD) if (mMethodsCallbacks.count(methodID)) { // Method std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID); - return onRemoteCall(*socketPtr, methodID, messageID, methodCallbacks); + return onRemoteMethod(*socketPtr, methodID, messageID, methodCallbacks); } else if (mSignalsCallbacks.count(methodID)) { // Signal @@ -428,7 +425,6 @@ bool Processor::onReturnValue(const Socket& socket, { LOGS(mLogPrefix + "Processor onReturnValue messageID: " << messageID); - // LOGI(mLogPrefix + "Return value for messageID: " << messageID); ReturnCallbacks returnCallbacks; try { LOGT(mLogPrefix + "Getting the return callback"); @@ -454,11 +450,9 @@ bool Processor::onReturnValue(const Socket& socket, return true; } - // LOGT(mLogPrefix + "Process return value callback for messageID: " << messageID); ResultBuilder resultBuilder(data); IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); - // LOGT(mLogPrefix + "Return value for messageID: " << messageID << " processed"); return false; } @@ -469,8 +463,6 @@ bool Processor::onRemoteSignal(const Socket& socket, { LOGS(mLogPrefix + "Processor onRemoteSignal; methodID: " << methodID << " messageID: " << messageID); - // LOGI(mLogPrefix + "Processor onRemoteSignal; methodID: " << methodID << " messageID: " << messageID); - std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming data"); @@ -482,7 +474,6 @@ bool Processor::onRemoteSignal(const Socket& socket, return true; } - // LOGT(mLogPrefix + "Signal callback for methodID: " << methodID << "; messageID: " << messageID); try { signalCallbacks->signal(socket.getFD(), data); } catch (const IPCUserException& e) { @@ -499,13 +490,12 @@ bool Processor::onRemoteSignal(const Socket& socket, return false; } -bool Processor::onRemoteCall(const Socket& socket, - const MethodID methodID, - const MessageID messageID, - std::shared_ptr methodCallbacks) +bool Processor::onRemoteMethod(const Socket& socket, + const MethodID methodID, + const MessageID messageID, + std::shared_ptr methodCallbacks) { - LOGS(mLogPrefix + "Processor onRemoteCall; methodID: " << methodID << " messageID: " << messageID); - // LOGI(mLogPrefix + "Remote call; methodID: " << methodID << " messageID: " << messageID); + LOGS(mLogPrefix + "Processor onRemoteMethod; methodID: " << methodID << " messageID: " << messageID); std::shared_ptr data; try { @@ -681,9 +671,6 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) request.peerFD, data); - - resetPolling(); - if (mNewPeerCallback) { // Notify about the new user. LOGT(mLogPrefix + "Calling NewPeerCallback"); diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index b6bd615..a77c072 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -84,7 +84,6 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500; * - no new events added after stop() called * - when using IPCGSource: addFD and removeFD can be called from addPeer removePeer callbacks, but * there is no mechanism to ensure the IPCSource exists.. therefore SIGSEGV :) -* - remove recursive mutex * */ class Processor { @@ -176,13 +175,6 @@ public: FileDescriptor addPeer(const std::shared_ptr& socketPtr); /** - * Request removing peer and wait - * - * @param peerFD id of the peer - */ - void removePeer(const FileDescriptor peerFD); - - /** * 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. @@ -302,7 +294,7 @@ public: private: typedef std::function& data)> SerializeCallback; typedef std::function(int fd)> ParseCallback; - typedef std::unique_lock Lock; + typedef std::unique_lock Lock; typedef RequestQueue::Request Request; struct EmptyData { @@ -394,7 +386,7 @@ private: std::unordered_map mReturnCallbacks; // Mutex for modifying any internal data - std::recursive_mutex mStateMutex; + std::mutex mStateMutex; PeerCallback mNewPeerCallback; PeerCallback mRemovedPeerCallback; @@ -430,10 +422,10 @@ private: bool onReturnValue(const Socket& socket, const MessageID messageID); - bool onRemoteCall(const Socket& socket, - const MethodID methodID, - const MessageID messageID, - std::shared_ptr methodCallbacks); + bool onRemoteMethod(const Socket& socket, + const MethodID methodID, + const MessageID messageID, + std::shared_ptr methodCallbacks); bool onRemoteSignal(const Socket& socket, const MethodID methodID, const MessageID messageID, @@ -441,6 +433,7 @@ private: void resetPolling(); FileDescriptor getNextFileDescriptor(); void removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr); + void removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock); void onNewSignals(const FileDescriptor peerFD, std::shared_ptr& data); @@ -528,7 +521,6 @@ void Processor::setSignalHandler(const MethodID methodID, } std::shared_ptr data; - std::vector peerFDs; { Lock lock(mStateMutex); @@ -546,15 +538,11 @@ void Processor::setSignalHandler(const MethodID methodID, data = std::make_shared(ids); for (const auto kv : mSockets) { - peerFDs.push_back(kv.first); + signalInternal(REGISTER_SIGNAL_METHOD_ID, + kv.first, + data); } } - - for (const auto peerFD : peerFDs) { - signalInternal(REGISTER_SIGNAL_METHOD_ID, - peerFD, - data); - } } @@ -578,12 +566,10 @@ std::shared_ptr Processor::callSync(const MethodID methodID, unsigned int timeoutMS) { Result result; - - std::mutex mutex; std::condition_variable cv; - auto process = [&result, &mutex, &cv](const Result && r) { - std::unique_lock lock(mutex); + auto process = [&result, &cv](const Result && r) { + // This is called under lock(mStateMutex) result = std::move(r); cv.notify_all(); }; @@ -597,27 +583,21 @@ std::shared_ptr Processor::callSync(const MethodID methodID, return result.isValid(); }; - std::unique_lock lock(mutex); + Lock lock(mStateMutex); LOGT(mLogPrefix + "Waiting for the response..."); if (!cv.wait_for(lock, std::chrono::milliseconds(timeoutMS), isResultInitialized)) { LOGW(mLogPrefix + "Probably a timeout in callSync. Checking..."); - bool isTimeout; - { - Lock lock(mStateMutex); - // Call isn't sent or call is sent but there is no reply - isTimeout = mRequestQueue.removeIf([messageID](Request & request) { - return request.requestID == Event::METHOD && - request.get()->messageID == messageID; - }) - || mRequestQueue.removeIf([messageID](Request & request) { - return request.requestID == Event::SIGNAL && - request.get()->messageID == messageID; - }) - || 1 == mReturnCallbacks.erase(messageID); - } + + // Call isn't sent or call is sent but there is no reply + bool isTimeout = mRequestQueue.removeIf([messageID](Request & request) { + return request.requestID == Event::METHOD && + request.get()->messageID == messageID; + }) + || 1 == mReturnCallbacks.erase(messageID); + if (isTimeout) { LOGE(mLogPrefix + "Function call timeout; methodID: " << methodID); - removePeer(peerFD); + removePeerSyncInternal(peerFD, lock); throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID)); } else { LOGW(mLogPrefix + "Timeout started during the return value processing, so wait for it to finish"); @@ -636,7 +616,6 @@ void Processor::signalInternal(const MethodID methodID, const FileDescriptor peerFD, const std::shared_ptr& data) { - Lock lock(mStateMutex); auto request = SignalRequest::create(methodID, peerFD, data); mRequestQueue.pushFront(Event::SIGNAL, request); } diff --git a/common/ipc/internals/remove-peer-request.hpp b/common/ipc/internals/remove-peer-request.hpp index 4ec07cb..900a8a0 100644 --- a/common/ipc/internals/remove-peer-request.hpp +++ b/common/ipc/internals/remove-peer-request.hpp @@ -39,14 +39,14 @@ public: RemovePeerRequest& operator=(const RemovePeerRequest&) = delete; RemovePeerRequest(const FileDescriptor peerFD, - const std::shared_ptr& conditionPtr) + const std::shared_ptr& conditionPtr) : peerFD(peerFD), conditionPtr(conditionPtr) { } FileDescriptor peerFD; - std::shared_ptr conditionPtr; + std::shared_ptr conditionPtr; }; } // namespace ipc -- 2.7.4 From 9c9047d89cd4c3bef15e2b76f7a9276ae158038e Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 2 Feb 2015 12:41:50 +0100 Subject: [PATCH 13/16] Fix test case ConfigurationSuite/FromKVWithDefaultsTest [Bug/Feature] ConfigurationSuite/FromKVWithDefaultsTest fail [Cause] No field in sample json string [Solution] Added required field [Verification] Run ConfigurationSuite tests Change-Id: I113f76f2d2edb700a490241d6993a8e3a506a47b --- tests/unit_tests/config/testconfig-example.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit_tests/config/testconfig-example.hpp b/tests/unit_tests/config/testconfig-example.hpp index c05b63c..6c14719 100644 --- a/tests/unit_tests/config/testconfig-example.hpp +++ b/tests/unit_tests/config/testconfig-example.hpp @@ -168,6 +168,7 @@ const std::string jsonEmptyTestString = "\"emptyIntVector\": [ ], " "\"intVector\": [ ], " "\"stringVector\": [ ], " + "\"doubleVector\": [ ], " "\"subObj\": { \"intVal\": 0, \"intVector\": [ ], \"subSubObj\": { \"intVal\": 0 } }, " "\"subVector\": [ ], " "\"union1\": { \"type\": \"int\", \"value\": 0 }, " -- 2.7.4 From ef0613f3ea30f054f7dce5a333fdaf01ff6372e9 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Wed, 4 Feb 2015 12:11:35 +0100 Subject: [PATCH 14/16] Fix generating IP and VT for new zones [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Run tests, run daemon and add/remove some zones. Change-Id: I9754ab249bb65d8407f1220d0804d2ddc0fad798 --- server/configs/daemon.conf.in | 1 + server/zones-manager-config.hpp | 6 ++++ server/zones-manager.cpp | 34 ++++++++++++++++------ server/zones-manager.hpp | 1 + .../configs/ut-client/test-dbus-daemon.conf.in | 1 + .../server/configs/ut-server/buggy-daemon.conf.in | 1 + .../server/configs/ut-server/test-daemon.conf.in | 1 + .../configs/ut-zones-manager/buggy-daemon.conf.in | 1 + .../ut-zones-manager/empty-dbus-daemon.conf.in | 1 + .../configs/ut-zones-manager/test-daemon.conf.in | 1 + .../ut-zones-manager/test-dbus-daemon.conf.in | 1 + 11 files changed, 40 insertions(+), 9 deletions(-) diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index ea2d457..2040ccf 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -8,6 +8,7 @@ "runMountPointPrefix" : "/var/run/zones", "defaultId" : "", "lxcTemplatePrefix" : "/etc/vasum/lxc-templates", + "availableVTs" : [3, 4, 5, 6], "inputConfig" : {"enabled" : true, "device" : "gpio_keys.6", "code" : 116, diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index 19da74a..38c17ac 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -69,6 +69,11 @@ struct ZonesManagerConfig { */ std::string lxcTemplatePrefix; + /** + * VTs available for zones + */ + std::vector availableVTs; + /* * Parameters describing input device used to switch between zones */ @@ -92,6 +97,7 @@ struct ZonesManagerConfig { zoneTemplatePath, zoneNewConfigPrefix, lxcTemplatePrefix, + availableVTs, inputConfig, runMountPointPrefix, proxyCallRules diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index a31a0f3..f554bdc 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -73,7 +73,6 @@ const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~"); const boost::regex ZONE_VT_REGEX("~VT~"); const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100; -const unsigned int ZONE_VT_BASE = 1; std::string getConfigName(const std::string& zoneId) { @@ -890,6 +889,7 @@ void ZonesManager::generateNewConfig(const std::string& id, const std::string& templatePath, const std::string& resultPath) { + // TODO Do not store new config at all, use template and dynamic config instead namespace fs = boost::filesystem; if (fs::exists(resultPath)) { @@ -913,18 +913,16 @@ void ZonesManager::generateNewConfig(const std::string& id, std::string resultConfig = boost::regex_replace(config, ZONE_NAME_REGEX, id); + // generate first free VT number + const int freeVT = getVTForNewZone(); + LOGD("VT number: " << freeVT); + resultConfig = boost::regex_replace(resultConfig, ZONE_VT_REGEX, std::to_string(freeVT)); + // generate third IP octet for network config - // TODO change algorithm after implementing removeZone - std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + mZones.size() + 1); + std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); LOGD("IP third octet: " << thirdOctetStr); resultConfig = boost::regex_replace(resultConfig, ZONE_IP_THIRD_OCTET_REGEX, thirdOctetStr); - // generate first free VT number - // TODO change algorithm after implementing removeZone - std::string freeVT = std::to_string(ZONE_VT_BASE + mZones.size() + 1); - LOGD("VT number: " << freeVT); - resultConfig = boost::regex_replace(resultConfig, ZONE_VT_REGEX, freeVT); - if (!utils::saveFileContent(resultPath, resultConfig)) { LOGE("Faield to save new config file."); throw ZoneOperationException("Failed to save new config file."); @@ -936,6 +934,24 @@ void ZonesManager::generateNewConfig(const std::string& id, fs::perms::others_read); } +int ZonesManager::getVTForNewZone() +{ + if (mConfig.availableVTs.empty()) { + return -1; + } + std::set candidates(mConfig.availableVTs.begin(), mConfig.availableVTs.end()); + // exclude all used + for (auto& zone : mZones) { + candidates.erase(zone->getVT()); + } + if (candidates.empty()) { + LOGE("No free VT for zone"); + throw ZoneOperationException("No free VT for zone"); + } + // return the smallest + return *candidates.begin(); +} + void ZonesManager::handleCreateZoneCall(const std::string& id, dbus::MethodResultBuilder::Pointer result) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index b46768f..740e074 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -134,6 +134,7 @@ private: void generateNewConfig(const std::string& id, const std::string& templatePath, const std::string& resultPath); + int getVTForNewZone(); void notifyActiveZoneHandler(const std::string& caller, const std::string& appliaction, diff --git a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in index e0af664..debc303 100644 --- a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in +++ b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf.in @@ -10,6 +10,7 @@ "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/client/ut-client/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in index bf274de..8deaa6f 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf.in @@ -8,6 +8,7 @@ "runMountPointPrefix" : "", "defaultId" : "ut-server-zone1", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in index e1a67e8..7066583 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf.in @@ -8,6 +8,7 @@ "runMountPointPrefix" : "", "defaultId" : "ut-server-zone1", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "gpio-keys.4", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in index d07ab4c..a1fe350 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/buggy-daemon.conf.in @@ -8,6 +8,7 @@ "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in index 943ade9..21faee1 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/empty-dbus-daemon.conf.in @@ -8,6 +8,7 @@ "zoneNewConfigPrefix" : "/tmp/ut-zones/generated-configs/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in index f3cddde..73da57f 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-daemon.conf.in @@ -8,6 +8,7 @@ "zoneTemplatePath" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/templates/template.conf", "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in index fc47ff9..3305552 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/test-dbus-daemon.conf.in @@ -10,6 +10,7 @@ "zoneNewConfigPrefix" : "@VSM_TEST_CONFIG_INSTALL_DIR@/server/ut-zones-manager/", "runMountPointPrefix" : "", "lxcTemplatePrefix" : "@VSM_TEST_LXC_TEMPLATES_INSTALL_DIR@", + "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, -- 2.7.4 From f5a57b28e51aea11064d1c071e14127e5e8fcf35 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 5 Feb 2015 14:54:21 +0100 Subject: [PATCH 15/16] Update KVStore unit tests [Bug/Feature] N/A [Cause] libConfig has been changed [Solution] N/A [Verification] Run tests Change-Id: Ib958bb74160b5025c410ac3d60a3f21a12b663d2 --- tests/unit_tests/config/ut-kvstore.cpp | 87 ++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/tests/unit_tests/config/ut-kvstore.cpp b/tests/unit_tests/config/ut-kvstore.cpp index af2fa29..1129bdf 100644 --- a/tests/unit_tests/config/ut-kvstore.cpp +++ b/tests/unit_tests/config/ut-kvstore.cpp @@ -226,27 +226,84 @@ BOOST_AUTO_TEST_CASE(ClearTest) BOOST_AUTO_TEST_CASE(TransactionTest) { - auto t1 = c.getTransaction(); - BOOST_CHECK_EQUAL(t1.use_count(), 1); + { + KVStore::Transaction trans(c); + c.set(KEY, 1); + trans.commit(); + } + BOOST_CHECK_EQUAL(c.get(KEY), 1); + + { + KVStore::Transaction trans(c); + c.set(KEY, 2); + // no commit + } + BOOST_CHECK_EQUAL(c.get(KEY), 1); + + { + KVStore::Transaction trans(c); + trans.commit(); + BOOST_CHECK_THROW(trans.commit(), ConfigException); + BOOST_CHECK_THROW(KVStore::Transaction{c}, ConfigException); + } +} + +BOOST_AUTO_TEST_CASE(TransactionStackedTest) +{ + { + KVStore::Transaction transOuter(c); + KVStore::Transaction transInner(c); + } + + { + KVStore::Transaction transOuter(c); + { + KVStore::Transaction transInner(c); + c.set(KEY, 1); + // no inner commit + } + transOuter.commit(); + } + BOOST_CHECK_EQUAL(c.get(KEY), 1); - auto t2 = c.getTransaction(); - BOOST_CHECK_EQUAL(t1.use_count(), 2); - BOOST_CHECK_EQUAL(t2.use_count(), 2); + { + KVStore::Transaction transOuter(c); + { + KVStore::Transaction transInner(c); + c.set(KEY, 2); + transInner.commit(); + } + // no outer commit + } + BOOST_CHECK_EQUAL(c.get(KEY), 1); + + { + KVStore::Transaction transOuter(c); + KVStore::Transaction transInner(c); + transOuter.commit(); + BOOST_CHECK_THROW(transInner.commit(), ConfigException); + } } -BOOST_AUTO_TEST_CASE(TransactionTwoThreadsTest) +BOOST_AUTO_TEST_CASE(TransactionThreadsTest) { - Latch latch; - auto trans1 = c.getTransaction(); - std::thread thread([&]{ - auto trans2 = c.getTransaction(); - latch.set(); + Latch trans1Started, trans1Release, trans2Released; + std::thread thread1([&] { + KVStore::Transaction trans1(c); + trans1Started.set(); + trans1Release.wait(); + }); + std::thread thread2([&] { + trans1Started.wait(); + KVStore::Transaction trans2(c); + trans2Released.set(); }); std::this_thread::sleep_for(std::chrono::milliseconds(100)); - BOOST_CHECK(latch.empty()); - trans1.reset(); - latch.wait(); - thread.join(); + BOOST_CHECK(trans2Released.empty()); + trans1Release.set(); + thread1.join(); + trans2Released.wait(); + thread2.join(); } BOOST_AUTO_TEST_CASE(KeyTest) -- 2.7.4 From c8038f545754766a82213e48b6cb98b281434b73 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 4 Feb 2015 14:26:31 +0100 Subject: [PATCH 16/16] IPC: Added unique PeerID to the API to identify peers [Bug/Feature] PeerCallback takes peer's ID and fd All API methods take PeerID Replaced unordered map with a vector [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: I352fd3942c4a2e6f7f5c891b1dcc0109d8bf7128 --- common/ipc/client.cpp | 10 +- common/ipc/client.hpp | 6 +- common/ipc/internals/add-peer-request.hpp | 8 +- common/ipc/internals/method-request.hpp | 16 +- common/ipc/internals/processor.cpp | 236 ++++++++++++++------------- common/ipc/internals/processor.hpp | 98 ++++++----- common/ipc/internals/remove-peer-request.hpp | 6 +- common/ipc/internals/signal-request.hpp | 14 +- common/ipc/service.cpp | 8 +- common/ipc/service.hpp | 16 +- common/ipc/types.cpp | 5 + common/ipc/types.hpp | 15 +- tests/unit_tests/ipc/ut-ipc.cpp | 69 ++++---- 13 files changed, 274 insertions(+), 233 deletions(-) diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp index 1b7ae56..51e59f8 100644 --- a/common/ipc/client.cpp +++ b/common/ipc/client.cpp @@ -61,7 +61,7 @@ void Client::start(const bool usesExternalPolling) LOGD("Connecting to " + mSocketPath); auto socketPtr = std::make_shared(Socket::connectSocket(mSocketPath)); - mServiceFD = mProcessor.addPeer(socketPtr); + mServiceID = mProcessor.addPeer(socketPtr); } bool Client::isStarted() @@ -123,12 +123,12 @@ void Client::handle(const FileDescriptor fd, const short pollEvent) void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Client setNewPeerCallback"); - auto callback = [newPeerCallback, this](FileDescriptor fd) { + auto callback = [newPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->addFD(fd); } if (newPeerCallback) { - newPeerCallback(fd); + newPeerCallback(peerID, fd); } }; mProcessor.setNewPeerCallback(callback); @@ -137,12 +137,12 @@ void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) void Client::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Client setRemovedPeerCallback"); - auto callback = [removedPeerCallback, this](FileDescriptor fd) { + auto callback = [removedPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->removeFD(fd); } if (removedPeerCallback) { - removedPeerCallback(fd); + removedPeerCallback(peerID, fd); } }; mProcessor.setRemovedPeerCallback(callback); diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index 1ee44bb..321b4da 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -174,7 +174,7 @@ private: void startPoll(); void stopPoll(); - FileDescriptor mServiceFD; + PeerID mServiceID; Processor mProcessor; std::string mSocketPath; IPCGSource::Pointer mIPCGSourcePtr; @@ -202,7 +202,7 @@ std::shared_ptr Client::callSync(const MethodID methodID, unsigned int timeoutMS) { LOGS("Client callSync, methodID: " << methodID << ", timeoutMS: " << timeoutMS); - return mProcessor.callSync(methodID, mServiceFD, data, timeoutMS); + return mProcessor.callSync(methodID, mServiceID, data, timeoutMS); } template @@ -213,7 +213,7 @@ void Client::callAsync(const MethodID methodID, LOGS("Client callAsync, methodID: " << methodID); mProcessor.callAsync(methodID, - mServiceFD, + mServiceID, data, resultCallback); } diff --git a/common/ipc/internals/add-peer-request.hpp b/common/ipc/internals/add-peer-request.hpp index 3409ba5..57ec06c 100644 --- a/common/ipc/internals/add-peer-request.hpp +++ b/common/ipc/internals/add-peer-request.hpp @@ -36,14 +36,14 @@ public: AddPeerRequest(const AddPeerRequest&) = delete; AddPeerRequest& operator=(const AddPeerRequest&) = delete; - AddPeerRequest(const FileDescriptor peerFD, const std::shared_ptr& socketPtr) - : peerFD(peerFD), - socketPtr(socketPtr) + AddPeerRequest(const std::shared_ptr& socketPtr) + : socketPtr(socketPtr), + peerID(getNextPeerID()) { } - FileDescriptor peerFD; std::shared_ptr socketPtr; + PeerID peerID; }; } // namespace ipc diff --git a/common/ipc/internals/method-request.hpp b/common/ipc/internals/method-request.hpp index 8ed17c5..8ec1223 100644 --- a/common/ipc/internals/method-request.hpp +++ b/common/ipc/internals/method-request.hpp @@ -42,12 +42,12 @@ public: template static std::shared_ptr create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); MethodID methodID; - FileDescriptor peerFD; + PeerID peerID; MessageID messageID; std::shared_ptr data; SerializeCallback serialize; @@ -55,9 +55,9 @@ public: ResultBuilderHandler process; private: - MethodRequest(const MethodID methodID, const FileDescriptor peerFD) + MethodRequest(const MethodID methodID, const PeerID peerID) : methodID(methodID), - peerFD(peerFD), + peerID(peerID), messageID(getNextMessageID()) {} }; @@ -65,21 +65,21 @@ private: template std::shared_ptr MethodRequest::create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { - std::shared_ptr request(new MethodRequest(methodID, peerFD)); + std::shared_ptr request(new MethodRequest(methodID, peerID)); request->data = data; request->serialize = [](const int fd, std::shared_ptr& data)->void { - LOGS("Method serialize, peerFD: " << fd); + LOGS("Method serialize, peerID: " << fd); config::saveToFD(fd, *std::static_pointer_cast(data)); }; request->parse = [](const int fd)->std::shared_ptr { - LOGS("Method parse, peerFD: " << fd); + LOGS("Method parse, peerID: " << fd); std::shared_ptr data(new ReceivedDataType()); config::loadFromFD(fd, *data); return data; diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 1f51d5e..d63e490 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -84,6 +84,20 @@ Processor::~Processor() } } +Processor::Peers::iterator Processor::getPeerInfoIterator(const FileDescriptor fd) +{ + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&fd](const PeerInfo & peerInfo) { + return fd == peerInfo.socketPtr->getFD(); + }); +} + +Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID peerID) +{ + return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [&peerID](const PeerInfo & peerInfo) { + return peerID == peerInfo.peerID; + }); +} + bool Processor::isStarted() { Lock lock(mStateMutex); @@ -155,55 +169,54 @@ void Processor::removeMethod(const MethodID methodID) mMethodsCallbacks.erase(methodID); } -FileDescriptor Processor::addPeer(const std::shared_ptr& socketPtr) +PeerID Processor::addPeer(const std::shared_ptr& socketPtr) { LOGS(mLogPrefix + "Processor addPeer"); Lock lock(mStateMutex); - FileDescriptor peerFD = socketPtr->getFD(); - auto request = std::make_shared(peerFD, socketPtr); - mRequestQueue.pushBack(Event::ADD_PEER, request); + auto requestPtr = std::make_shared(socketPtr); + mRequestQueue.pushBack(Event::ADD_PEER, requestPtr); - LOGI(mLogPrefix + "Add Peer Request. Id: " << peerFD); + LOGI(mLogPrefix + "Add Peer Request. Id: " << requestPtr->peerID); - return peerFD; + return requestPtr->peerID; } -void Processor::removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock) +void Processor::removePeerSyncInternal(const PeerID peerID, Lock& lock) { - LOGS(mLogPrefix + "Processor removePeer peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor removePeer peerID: " << peerID); - auto isPeerDeleted = [&peerFD, this]()->bool { - return mSockets.count(peerFD) == 0; + auto isPeerDeleted = [&peerID, this]()->bool { + return getPeerInfoIterator(peerID) == mPeerInfo.end(); }; - mRequestQueue.removeIf([peerFD](Request & request) { + mRequestQueue.removeIf([peerID](Request & request) { return request.requestID == Event::ADD_PEER && - request.get()->peerFD == peerFD; + request.get()->peerID == peerID; }); // Remove peer and wait till he's gone std::shared_ptr conditionPtr(new std::condition_variable()); - auto request = std::make_shared(peerFD, conditionPtr); + auto request = std::make_shared(peerID, conditionPtr); mRequestQueue.pushBack(Event::REMOVE_PEER, request); conditionPtr->wait(lock, isPeerDeleted); } -void Processor::removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr) +void Processor::removePeerInternal(Peers::iterator peerIt, const std::exception_ptr& exceptionPtr) { - LOGS(mLogPrefix + "Processor removePeerInternal peerFD: " << peerFD); - LOGI(mLogPrefix + "Removing peer. peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor removePeerInternal peerID: " << peerIt->peerID); + LOGI(mLogPrefix + "Removing peer. peerID: " << peerIt->peerID); - if (!mSockets.erase(peerFD)) { - LOGW(mLogPrefix + "No such peer. Another thread called removePeerInternal"); + if (peerIt == mPeerInfo.end()) { + LOGW("Peer already removed"); return; } // Remove from signal addressees for (auto it = mSignalsPeers.begin(); it != mSignalsPeers.end();) { - it->second.remove(peerFD); + it->second.remove(peerIt->peerID); if (it->second.empty()) { it = mSignalsPeers.erase(it); } else { @@ -213,7 +226,7 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, const std::excep // Erase associated return value callbacks for (auto it = mReturnCallbacks.begin(); it != mReturnCallbacks.end();) { - if (it->second.peerFD == peerFD) { + if (it->second.peerID == peerIt->peerID) { ResultBuilder resultBuilder(exceptionPtr); IGNORE_EXCEPTIONS(it->second.process(resultBuilder)); it = mReturnCallbacks.erase(it); @@ -224,8 +237,10 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, const std::excep if (mRemovedPeerCallback) { // Notify about the deletion - mRemovedPeerCallback(peerFD); + mRemovedPeerCallback(peerIt->peerID, peerIt->socketPtr->getFD()); } + + mPeerInfo.erase(peerIt); } void Processor::resetPolling() @@ -236,19 +251,20 @@ void Processor::resetPolling() return; } - LOGI(mLogPrefix + "Reseting mFDS.size: " << mSockets.size()); // Setup polling on eventfd and sockets - mFDs.resize(mSockets.size() + 1); + mFDs.resize(mPeerInfo.size() + 1); + LOGI(mLogPrefix + "Reseting mFDS.size: " << mFDs.size()); mFDs[0].fd = mRequestQueue.getFD(); mFDs[0].events = POLLIN; - auto socketIt = mSockets.begin(); for (unsigned int i = 1; i < mFDs.size(); ++i) { - LOGI(mLogPrefix + "Reseting fd: " << socketIt->second->getFD()); - mFDs[i].fd = socketIt->second->getFD(); + auto fd = mPeerInfo[i - 1].socketPtr->getFD(); + + LOGI(mLogPrefix + "Reseting fd: " << fd); + + mFDs[i].fd = fd; 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? } } @@ -306,25 +322,26 @@ bool Processor::handleLostConnections() Lock lock(mStateMutex); bool isPeerRemoved = false; - { - for (unsigned int i = 1; i < mFDs.size(); ++i) { - if (mFDs[i].revents & POLLHUP) { - LOGI(mLogPrefix + "Lost connection to peer: " << mFDs[i].fd); - mFDs[i].revents &= ~(POLLHUP); - removePeerInternal(mFDs[i].fd, - std::make_exception_ptr(IPCPeerDisconnectedException())); - isPeerRemoved = true; - } + + for (unsigned int i = 1; i < mFDs.size(); ++i) { + if (mFDs[i].revents & POLLHUP) { + auto peerIt = getPeerInfoIterator(mFDs[i].fd); + LOGI(mLogPrefix + "Lost connection to peer: " << peerIt->peerID); + mFDs[i].revents &= ~(POLLHUP); + removePeerInternal(peerIt, + std::make_exception_ptr(IPCPeerDisconnectedException())); + isPeerRemoved = true; } } return isPeerRemoved; } -bool Processor::handleLostConnection(const FileDescriptor peerFD) +bool Processor::handleLostConnection(const FileDescriptor fd) { Lock lock(mStateMutex); - removePeerInternal(peerFD, + auto peerIt = getPeerInfoIterator(fd); + removePeerInternal(peerIt, std::make_exception_ptr(IPCPeerDisconnectedException())); return true; } @@ -344,54 +361,53 @@ bool Processor::handleInputs() return pollChanged; } -bool Processor::handleInput(const FileDescriptor peerFD) +bool Processor::handleInput(const FileDescriptor fd) { - LOGS(mLogPrefix + "Processor handleInput peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor handleInput fd: " << fd); Lock lock(mStateMutex); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "No such peer: " << peerFD); + auto peerIt = getPeerInfoIterator(fd); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "No peer for fd: " << fd); return false; } + Socket& socket = *peerIt->socketPtr; + MethodID methodID; MessageID messageID; { - Socket::Guard guard = socketPtr->getGuard(); + Socket::Guard guard = socket.getGuard(); try { - socketPtr->read(&methodID, sizeof(methodID)); - socketPtr->read(&messageID, sizeof(messageID)); + socket.read(&methodID, sizeof(methodID)); + socket.read(&messageID, sizeof(messageID)); } catch (const IPCException& e) { LOGE(mLogPrefix + "Error during reading the socket"); - removePeerInternal(socketPtr->getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } if (methodID == RETURN_METHOD_ID) { - return onReturnValue(*socketPtr, messageID); + return onReturnValue(peerIt, messageID); } else { if (mMethodsCallbacks.count(methodID)) { // Method std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID); - return onRemoteMethod(*socketPtr, methodID, messageID, methodCallbacks); + return onRemoteMethod(peerIt, methodID, messageID, methodCallbacks); } else if (mSignalsCallbacks.count(methodID)) { // Signal std::shared_ptr signalCallbacks = mSignalsCallbacks.at(methodID); - return onRemoteSignal(*socketPtr, methodID, messageID, signalCallbacks); + return onRemoteSignal(peerIt, methodID, messageID, signalCallbacks); } else { - // Nothing LOGW(mLogPrefix + "No method or signal callback for methodID: " << methodID); - removePeerInternal(socketPtr->getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -399,20 +415,20 @@ bool Processor::handleInput(const FileDescriptor peerFD) } } -void Processor::onNewSignals(const FileDescriptor peerFD, - std::shared_ptr& data) +void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) { - LOGS(mLogPrefix + "Processor onNewSignals peerFD: " << peerFD); + LOGS(mLogPrefix + "Processor onNewSignals peerID: " << peerID); for (const MethodID methodID : data->ids) { - mSignalsPeers[methodID].push_back(peerFD); + mSignalsPeers[methodID].push_back(peerID); } } -void Processor::onErrorSignal(const FileDescriptor, std::shared_ptr& data) +void Processor::onErrorSignal(const PeerID, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onErrorSignal messageID: " << data->messageID); + // If there is no return callback an out_of_range error will be thrown and peer will be removed ReturnCallbacks returnCallbacks = std::move(mReturnCallbacks.at(data->messageID)); mReturnCallbacks.erase(data->messageID); @@ -420,7 +436,7 @@ void Processor::onErrorSignal(const FileDescriptor, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming return data"); - data = returnCallbacks.parse(socket.getFD()); + data = returnCallbacks.parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); ResultBuilder resultBuilder(std::make_exception_ptr(IPCParsingException())); IGNORE_EXCEPTIONS(returnCallbacks.process(resultBuilder)); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } @@ -456,7 +472,7 @@ bool Processor::onReturnValue(const Socket& socket, return false; } -bool Processor::onRemoteSignal(const Socket& socket, +bool Processor::onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr signalCallbacks) @@ -466,22 +482,22 @@ bool Processor::onRemoteSignal(const Socket& socket, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming data"); - data = signalCallbacks->parse(socket.getFD()); + data = signalCallbacks->parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } try { - signalCallbacks->signal(socket.getFD(), data); + signalCallbacks->signal(peerIt->peerID, data); } catch (const IPCUserException& e) { LOGW("Discarded user's exception"); return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; @@ -490,7 +506,7 @@ bool Processor::onRemoteSignal(const Socket& socket, return false; } -bool Processor::onRemoteMethod(const Socket& socket, +bool Processor::onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr methodCallbacks) @@ -500,10 +516,10 @@ bool Processor::onRemoteMethod(const Socket& socket, std::shared_ptr data; try { LOGT(mLogPrefix + "Parsing incoming data"); - data = methodCallbacks->parse(socket.getFD()); + data = methodCallbacks->parse(peerIt->socketPtr->getFD()); } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception during parsing: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCParsingException())); return true; } @@ -511,15 +527,15 @@ bool Processor::onRemoteMethod(const Socket& socket, LOGT(mLogPrefix + "Process callback for methodID: " << methodID << "; messageID: " << messageID); std::shared_ptr returnData; try { - returnData = methodCallbacks->method(socket.getFD(), data); + returnData = methodCallbacks->method(peerIt->peerID, data); } catch (const IPCUserException& e) { LOGW("User's exception"); auto data = std::make_shared(messageID, e.getCode(), e.what()); - signalInternal(ERROR_METHOD_ID, socket.getFD(), data); + signalInternal(ERROR_METHOD_ID, peerIt->peerID, data); return false; } catch (const std::exception& e) { LOGE(mLogPrefix + "Exception in method handler: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } @@ -527,13 +543,14 @@ bool Processor::onRemoteMethod(const Socket& socket, LOGT(mLogPrefix + "Sending return data; methodID: " << methodID << "; messageID: " << messageID); try { // Send the call with the socket + Socket& socket = *peerIt->socketPtr; 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 std::exception& e) { LOGE(mLogPrefix + "Exception during serialization: " << e.what()); - removePeerInternal(socket.getFD(), + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); return true; @@ -565,13 +582,11 @@ bool Processor::handleEvent() bool Processor::onMethodRequest(MethodRequest& request) { LOGS(mLogPrefix + "Processor onMethodRequest"); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(request.peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "Peer disconnected. No socket with a peerFD: " << request.peerFD); + auto peerIt = getPeerInfoIterator(request.peerID); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "Peer disconnected. No user with a peerID: " << request.peerID); // Pass the error to the processing callback ResultBuilder resultBuilder(std::make_exception_ptr(IPCPeerDisconnectedException())); @@ -583,17 +598,18 @@ bool Processor::onMethodRequest(MethodRequest& request) if (mReturnCallbacks.count(request.messageID) != 0) { LOGE(mLogPrefix + "There already was a return callback for messageID: " << request.messageID); } - mReturnCallbacks[request.messageID] = std::move(ReturnCallbacks(request.peerFD, + mReturnCallbacks[request.messageID] = std::move(ReturnCallbacks(peerIt->peerID, std::move(request.parse), std::move(request.process))); + Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket - Socket::Guard guard = socketPtr->getGuard(); - socketPtr->write(&request.methodID, sizeof(request.methodID)); - socketPtr->write(&request.messageID, sizeof(request.messageID)); + Socket::Guard guard = socket.getGuard(); + socket.write(&request.methodID, sizeof(request.methodID)); + socket.write(&request.messageID, sizeof(request.messageID)); LOGT(mLogPrefix + "Serializing the message"); - request.serialize(socketPtr->getFD(), request.data); + request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a method: " << e.what()); @@ -603,10 +619,8 @@ bool Processor::onMethodRequest(MethodRequest& request) mReturnCallbacks.erase(request.messageID); - removePeerInternal(request.peerFD, + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); - - return true; } @@ -618,27 +632,25 @@ bool Processor::onSignalRequest(SignalRequest& request) { LOGS(mLogPrefix + "Processor onSignalRequest"); - std::shared_ptr socketPtr; - try { - // Get the peer's socket - socketPtr = mSockets.at(request.peerFD); - } catch (const std::out_of_range&) { - LOGE(mLogPrefix + "Peer disconnected. No socket with a peerFD: " << request.peerFD); + auto peerIt = getPeerInfoIterator(request.peerID); + + if (peerIt == mPeerInfo.end()) { + LOGE(mLogPrefix + "Peer disconnected. No user for peerID: " << request.peerID); return false; } + Socket& socket = *peerIt->socketPtr; try { // Send the call with the socket - Socket::Guard guard = socketPtr->getGuard(); - socketPtr->write(&request.methodID, sizeof(request.methodID)); - socketPtr->write(&request.messageID, sizeof(request.messageID)); - request.serialize(socketPtr->getFD(), request.data); + Socket::Guard guard = socket.getGuard(); + socket.write(&request.methodID, sizeof(request.methodID)); + socket.write(&request.messageID, sizeof(request.messageID)); + request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a signal: " << e.what()); - removePeerInternal(request.peerFD, + removePeerInternal(peerIt, std::make_exception_ptr(IPCSerializationException())); - return true; } @@ -649,16 +661,18 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) { LOGS(mLogPrefix + "Processor onAddPeerRequest"); - if (mSockets.size() > mMaxNumberOfPeers) { - LOGE(mLogPrefix + "There are too many peers. I don't accept the connection with " << request.peerFD); + if (mPeerInfo.size() > mMaxNumberOfPeers) { + LOGE(mLogPrefix + "There are too many peers. I don't accept the connection with " << request.peerID); return false; } - if (mSockets.count(request.peerFD) != 0) { - LOGE(mLogPrefix + "There already was a socket for peerFD: " << request.peerFD); + + if (getPeerInfoIterator(request.peerID) != mPeerInfo.end()) { + LOGE(mLogPrefix + "There already was a socket for peerID: " << request.peerID); return false; } - mSockets[request.peerFD] = std::move(request.socketPtr); + PeerInfo peerInfo(request.peerID, request.socketPtr); + mPeerInfo.push_back(std::move(peerInfo)); // Sending handled signals @@ -668,16 +682,16 @@ bool Processor::onAddPeerRequest(AddPeerRequest& request) } auto data = std::make_shared(ids); signalInternal(REGISTER_SIGNAL_METHOD_ID, - request.peerFD, + request.peerID, data); if (mNewPeerCallback) { // Notify about the new user. LOGT(mLogPrefix + "Calling NewPeerCallback"); - mNewPeerCallback(request.peerFD); + mNewPeerCallback(request.peerID, request.socketPtr->getFD()); } - LOGI(mLogPrefix + "New peer: " << request.peerFD); + LOGI(mLogPrefix + "New peerID: " << request.peerID); return true; } @@ -685,7 +699,7 @@ bool Processor::onRemovePeerRequest(RemovePeerRequest& request) { LOGS(mLogPrefix + "Processor onRemovePeer"); - removePeerInternal(request.peerFD, + removePeerInternal(getPeerInfoIterator(request.peerID), std::make_exception_ptr(IPCRemovedPeerException())); request.conditionPtr->notify_all(); diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index a77c072..604d863 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -170,9 +170,9 @@ public: * Calls the newPeerCallback. * * @param socketPtr pointer to the new socket - * @return peerFD of the new socket + * @return peerID of the new user */ - FileDescriptor addPeer(const std::shared_ptr& socketPtr); + PeerID addPeer(const std::shared_ptr& socketPtr); /** * Saves the callbacks connected to the method id. @@ -219,7 +219,7 @@ public: * Synchronous method call. * * @param methodID API dependent id of the method - * @param peerFD id of the peer + * @param peerD 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 @@ -227,7 +227,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS = 500); @@ -235,7 +235,7 @@ public: * Asynchronous method call * * @param methodID API dependent id of the method - * @param peerFD id of the peer + * @param peerID id of the peer * @param data data to sent * @param process callback processing the return data * @tparam SentDataType data type to send @@ -243,7 +243,7 @@ public: */ template MessageID callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -265,19 +265,19 @@ public: * Removes one peer. * Handler used in external polling. * - * @param peerFD file description identifying the peer + * @param fd file description identifying the peer * @return should the polling structure be rebuild */ - bool handleLostConnection(const FileDescriptor peerFD); + bool handleLostConnection(const FileDescriptor fd); /** * Handles input from one peer. * Handler used in external polling. * - * @param peerFD file description identifying the peer + * @param fd file description identifying the peer * @return should the polling structure be rebuild */ - bool handleInput(const FileDescriptor peerFD); + bool handleInput(const FileDescriptor fd); /** * Handle one event from the internal event's queue @@ -361,14 +361,31 @@ private: ReturnCallbacks(ReturnCallbacks&&) = default; ReturnCallbacks& operator=(ReturnCallbacks &&) = default; - ReturnCallbacks(FileDescriptor peerFD, const ParseCallback& parse, const ResultBuilderHandler& process) - : peerFD(peerFD), parse(parse), process(process) {} + ReturnCallbacks(PeerID peerID, const ParseCallback& parse, const ResultBuilderHandler& process) + : peerID(peerID), parse(parse), process(process) {} - FileDescriptor peerFD; + PeerID peerID; ParseCallback parse; ResultBuilderHandler process; }; + struct PeerInfo { + PeerInfo(const PeerInfo& other) = delete; + PeerInfo& operator=(const PeerInfo&) = delete; + PeerInfo() = delete; + + PeerInfo(PeerInfo&&) = default; + PeerInfo& operator=(PeerInfo &&) = default; + + PeerInfo(PeerID peerID, const std::shared_ptr& socketPtr) + : peerID(peerID), socketPtr(socketPtr) {} + + PeerID peerID; + std::shared_ptr socketPtr; + }; + + typedef std::vector Peers; + std::string mLogPrefix; RequestQueue mRequestQueue; @@ -378,9 +395,9 @@ private: std::unordered_map> mMethodsCallbacks; std::unordered_map> mSignalsCallbacks; - std::unordered_map> mSignalsPeers; + std::unordered_map> mSignalsPeers; - std::unordered_map > mSockets; + Peers mPeerInfo; std::vector mFDs; std::unordered_map mReturnCallbacks; @@ -405,7 +422,7 @@ private: template void signalInternal(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data); void run(); @@ -420,27 +437,30 @@ private: bool handleLostConnections(); bool handleInputs(); - bool onReturnValue(const Socket& socket, + bool onReturnValue(Peers::iterator& peerIt, const MessageID messageID); - bool onRemoteMethod(const Socket& socket, + bool onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr methodCallbacks); - bool onRemoteSignal(const Socket& socket, + bool onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, const MessageID messageID, std::shared_ptr signalCallbacks); void resetPolling(); - FileDescriptor getNextFileDescriptor(); - void removePeerInternal(const FileDescriptor peerFD, const std::exception_ptr& exceptionPtr); - void removePeerSyncInternal(const FileDescriptor peerFD, Lock& lock); - void onNewSignals(const FileDescriptor peerFD, + void removePeerInternal(Peers::iterator peerIt, + const std::exception_ptr& exceptionPtr); + void removePeerSyncInternal(const PeerID peerID, Lock& lock); + + void onNewSignals(const PeerID peerID, std::shared_ptr& data); - void onErrorSignal(const FileDescriptor peerFD, + void onErrorSignal(const PeerID peerID, std::shared_ptr& data); + Peers::iterator getPeerInfoIterator(const FileDescriptor fd); + Peers::iterator getPeerInfoIterator(const PeerID peerID); }; @@ -460,9 +480,9 @@ void Processor::setMethodHandlerInternal(const MethodID methodID, config::saveToFD(fd, *std::static_pointer_cast(data)); }; - methodCall.method = [method](const FileDescriptor peerFD, std::shared_ptr& data)->std::shared_ptr { + methodCall.method = [method](const PeerID peerID, std::shared_ptr& data)->std::shared_ptr { std::shared_ptr tmpData = std::static_pointer_cast(data); - return method(peerFD, tmpData); + return method(peerID, tmpData); }; mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall)); @@ -502,9 +522,9 @@ void Processor::setSignalHandlerInternal(const MethodID methodID, return dataToFill; }; - signalCall.signal = [handler](const FileDescriptor peerFD, std::shared_ptr& dataReceived) { + signalCall.signal = [handler](const PeerID peerID, std::shared_ptr& dataReceived) { std::shared_ptr tmpData = std::static_pointer_cast(dataReceived); - handler(peerFD, tmpData); + handler(peerID, tmpData); }; mSignalsCallbacks[methodID] = std::make_shared(std::move(signalCall)); @@ -537,9 +557,9 @@ void Processor::setSignalHandler(const MethodID methodID, std::vector ids {methodID}; data = std::make_shared(ids); - for (const auto kv : mSockets) { + for (const PeerInfo& peerInfo : mPeerInfo) { signalInternal(REGISTER_SIGNAL_METHOD_ID, - kv.first, + peerInfo.peerID, data); } } @@ -548,12 +568,12 @@ void Processor::setSignalHandler(const MethodID methodID, template MessageID Processor::callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { Lock lock(mStateMutex); - auto request = MethodRequest::create(methodID, peerFD, data, process); + auto request = MethodRequest::create(methodID, peerID, data, process); mRequestQueue.pushBack(Event::METHOD, request); return request->messageID; } @@ -561,7 +581,7 @@ MessageID Processor::callAsync(const MethodID methodID, template std::shared_ptr Processor::callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -575,7 +595,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, }; MessageID messageID = callAsync(methodID, - peerFD, + peerID, data, process); @@ -597,7 +617,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, if (isTimeout) { LOGE(mLogPrefix + "Function call timeout; methodID: " << methodID); - removePeerSyncInternal(peerFD, lock); + removePeerSyncInternal(peerID, lock); throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID)); } else { LOGW(mLogPrefix + "Timeout started during the return value processing, so wait for it to finish"); @@ -613,10 +633,10 @@ std::shared_ptr Processor::callSync(const MethodID methodID, template void Processor::signalInternal(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data) { - auto request = SignalRequest::create(methodID, peerFD, data); + auto request = SignalRequest::create(methodID, peerID, data); mRequestQueue.pushFront(Event::SIGNAL, request); } @@ -630,8 +650,8 @@ void Processor::signal(const MethodID methodID, LOGW(mLogPrefix + "No peer is handling signal with methodID: " << methodID); return; } - for (const FileDescriptor peerFD : it->second) { - auto request = SignalRequest::create(methodID, peerFD, data); + for (const PeerID peerID : it->second) { + auto request = SignalRequest::create(methodID, peerID, data); mRequestQueue.pushBack(Event::SIGNAL, request); } } diff --git a/common/ipc/internals/remove-peer-request.hpp b/common/ipc/internals/remove-peer-request.hpp index 900a8a0..6ef8eca 100644 --- a/common/ipc/internals/remove-peer-request.hpp +++ b/common/ipc/internals/remove-peer-request.hpp @@ -38,14 +38,14 @@ public: RemovePeerRequest(const RemovePeerRequest&) = delete; RemovePeerRequest& operator=(const RemovePeerRequest&) = delete; - RemovePeerRequest(const FileDescriptor peerFD, + RemovePeerRequest(const PeerID peerID, const std::shared_ptr& conditionPtr) - : peerFD(peerFD), + : peerID(peerID), conditionPtr(conditionPtr) { } - FileDescriptor peerFD; + PeerID peerID; std::shared_ptr conditionPtr; }; diff --git a/common/ipc/internals/signal-request.hpp b/common/ipc/internals/signal-request.hpp index ad80d91..8a11ee8 100644 --- a/common/ipc/internals/signal-request.hpp +++ b/common/ipc/internals/signal-request.hpp @@ -41,19 +41,19 @@ public: template static std::shared_ptr create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data); MethodID methodID; - FileDescriptor peerFD; + PeerID peerID; MessageID messageID; std::shared_ptr data; SerializeCallback serialize; private: - SignalRequest(const MethodID methodID, const FileDescriptor peerFD) + SignalRequest(const MethodID methodID, const PeerID peerID) : methodID(methodID), - peerFD(peerFD), + peerID(peerID), messageID(getNextMessageID()) {} @@ -61,15 +61,15 @@ private: template std::shared_ptr SignalRequest::create(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data) { - std::shared_ptr request(new SignalRequest(methodID, peerFD)); + std::shared_ptr request(new SignalRequest(methodID, peerID)); request->data = data; request->serialize = [](const int fd, std::shared_ptr& data)->void { - LOGS("Signal serialize, peerFD: " << fd); + LOGS("Signal serialize, peerID: " << fd); config::saveToFD(fd, *std::static_pointer_cast(data)); }; diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index 9bf721b..d945f73 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -142,12 +142,12 @@ void Service::handle(const FileDescriptor fd, const short pollEvent) void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Service setNewPeerCallback"); - auto callback = [newPeerCallback, this](FileDescriptor fd) { + auto callback = [newPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->addFD(fd); } if (newPeerCallback) { - newPeerCallback(fd); + newPeerCallback(peerID, fd); } }; mProcessor.setNewPeerCallback(callback); @@ -156,12 +156,12 @@ void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) void Service::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Service setRemovedPeerCallback"); - auto callback = [removedPeerCallback, this](FileDescriptor fd) { + auto callback = [removedPeerCallback, this](PeerID peerID, FileDescriptor fd) { if (mIPCGSourcePtr) { mIPCGSourcePtr->removeFD(fd); } if (removedPeerCallback) { - removedPeerCallback(fd); + removedPeerCallback(peerID, fd); } }; mProcessor.setRemovedPeerCallback(callback); diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 383c71d..022c9c9 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -143,7 +143,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS = 500); @@ -158,7 +158,7 @@ public: */ template void callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback); @@ -204,26 +204,26 @@ void Service::setSignalHandler(const MethodID methodID, template std::shared_ptr Service::callSync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, unsigned int timeoutMS) { LOGS("Service callSync, methodID: " << methodID - << ", peerFD: " << peerFD + << ", peerID: " << peerID << ", timeoutMS: " << timeoutMS); - return mProcessor.callSync(methodID, peerFD, data, timeoutMS); + return mProcessor.callSync(methodID, peerID, data, timeoutMS); } template void Service::callAsync(const MethodID methodID, - const FileDescriptor peerFD, + const PeerID peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback) { - LOGS("Service callAsync, methodID: " << methodID << ", peerFD: " << peerFD); + LOGS("Service callAsync, methodID: " << methodID << ", peerID: " << peerID); mProcessor.callAsync(methodID, - peerFD, + peerID, data, resultCallback); } diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp index a73a612..9854e0e 100644 --- a/common/ipc/types.cpp +++ b/common/ipc/types.cpp @@ -34,6 +34,7 @@ namespace ipc { namespace { std::atomic gLastMessageID(0); +std::atomic gLastPeerID(0); } // namespace MessageID getNextMessageID() @@ -41,6 +42,10 @@ MessageID getNextMessageID() return ++gLastMessageID; } +PeerID getNextPeerID() +{ + return ++gLastPeerID; +} } // namespace ipc diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index b5411b3..fe132ec 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -22,11 +22,10 @@ * @brief Types definitions */ -#ifndef COMMON_IPC_HANDLERS_HPP -#define COMMON_IPC_HANDLERS_HPP +#ifndef COMMON_IPC_TYPES_HPP +#define COMMON_IPC_TYPES_HPP #include "ipc/exception.hpp" - #include #include #include @@ -37,26 +36,28 @@ namespace ipc { typedef int FileDescriptor; typedef unsigned int MethodID; typedef unsigned int MessageID; +typedef unsigned int PeerID; -typedef std::function PeerCallback; +typedef std::function PeerCallback; typedef std::function& data)> SerializeCallback; typedef std::function(int fd)> ParseCallback; MessageID getNextMessageID(); +PeerID getNextPeerID(); template struct MethodHandler { - typedef std::function(FileDescriptor peerFD, + typedef std::function(PeerID peerID, std::shared_ptr& data)> type; }; template struct SignalHandler { - typedef std::function& data)> type; }; } // namespace ipc } // namespace vasum -#endif // COMMON_IPC_HANDLERS_HPP +#endif // COMMON_IPC_TYPES_HPP diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 5408735..cb475f1 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -136,33 +136,33 @@ struct ThrowOnAcceptData { } }; -std::shared_ptr returnEmptyCallback(const FileDescriptor, std::shared_ptr&) +std::shared_ptr returnEmptyCallback(const PeerID, std::shared_ptr&) { return std::make_shared(); } -std::shared_ptr returnDataCallback(const FileDescriptor, std::shared_ptr&) +std::shared_ptr returnDataCallback(const PeerID, std::shared_ptr&) { return std::make_shared(1); } -std::shared_ptr echoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr echoCallback(const PeerID, std::shared_ptr& data) { return std::make_shared(data->intVal); } -std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr& data) +std::shared_ptr longEchoCallback(const PeerID, std::shared_ptr& data) { std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME)); return std::make_shared(data->intVal); } -FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) +PeerID connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) { - // Connects the Client to the Service and returns Clients FileDescriptor - ValueLatch peerFDLatch; - auto newPeerCallback = [&peerFDLatch](const FileDescriptor newFD) { - peerFDLatch.set(newFD); + // Connects the Client to the Service and returns Clients PeerID + ValueLatch peerIDLatch; + auto newPeerCallback = [&peerIDLatch](const PeerID newID, const FileDescriptor) { + peerIDLatch.set(newID); }; s.setNewPeerCallback(newPeerCallback); @@ -173,18 +173,18 @@ FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool i c.start(isClientGlib); - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); + PeerID peerID = peerIDLatch.get(TIMEOUT); s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return peerFD; + BOOST_REQUIRE_NE(peerID, 0); + return peerID; } -FileDescriptor connectServiceGSource(Service& s, Client& c) +PeerID connectServiceGSource(Service& s, Client& c) { return connect(s, c, true, false); } -FileDescriptor connectClientGSource(Service& s, Client& c) +PeerID connectClientGSource(Service& s, Client& c) { return connect(s, c, false, true); } @@ -197,10 +197,10 @@ void testEcho(Client& c, const MethodID methodID) BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } -void testEcho(Service& s, const MethodID methodID, const FileDescriptor peerFD) +void testEcho(Service& s, const MethodID methodID, const PeerID peerID) { std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(methodID, peerFD, sentData, TIMEOUT); + std::shared_ptr recvData = s.callSync(methodID, peerID, sentData, TIMEOUT); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -244,17 +244,17 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) c.setMethodHandler(1, returnEmptyCallback); c.setMethodHandler(1, returnDataCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); c.setMethodHandler(1, echoCallback); c.setMethodHandler(2, returnDataCallback); - testEcho(s, 1, peerFD); + testEcho(s, 1, peerID); c.removeMethod(1); c.removeMethod(2); - BOOST_CHECK_THROW(testEcho(s, 1, peerFD), IPCException); + BOOST_CHECK_THROW(testEcho(s, 1, peerID), IPCException); } BOOST_AUTO_TEST_CASE(ServiceStartStop) @@ -333,10 +333,10 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); c.setMethodHandler(1, echoCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); std::shared_ptr sentData(new SendData(56)); - std::shared_ptr recvData = s.callSync(1, peerFD, sentData); + std::shared_ptr recvData = s.callSync(1, peerID, sentData); BOOST_REQUIRE(recvData); BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } @@ -372,14 +372,14 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); c.setMethodHandler(1, echoCallback); - FileDescriptor peerFD = connect(s, c); + PeerID peerID = connect(s, c); // Async call auto dataBack = [&recvDataLatch](Result && r) { recvDataLatch.set(r.get()); }; - s.callAsync(1, peerFD, sentData, dataBack); + s.callAsync(1, peerID, sentData, dataBack); // Wait for the response std::shared_ptr recvData(recvDataLatch.get(TIMEOUT)); @@ -431,7 +431,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) ValueLatch> retStatusLatch; Service s(socketPath); - auto method = [](const FileDescriptor, std::shared_ptr&) { + auto method = [](const PeerID, std::shared_ptr&) { return std::shared_ptr(new SendData(1)); }; @@ -462,7 +462,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) BOOST_AUTO_TEST_CASE(ReadTimeout) { Service s(socketPath); - auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { + auto longEchoCallback = [](const PeerID, std::shared_ptr& data) { return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); }; s.setMethodHandler(1, longEchoCallback); @@ -506,14 +506,15 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) Client c(socketPath); connect(s, c); - auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { recvDataLatchA.set(data); }; - auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr& data) { recvDataLatchB.set(data); }; + LOGH("SETTING SIGNAAALS"); c.setSignalHandler(1, handlerA); c.setSignalHandler(2, handlerB); @@ -541,11 +542,11 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) Service s(socketPath); Client c(socketPath); - auto handlerA = [&recvDataLatchA](const FileDescriptor, std::shared_ptr& data) { + auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr& data) { recvDataLatchA.set(data); }; - auto handlerB = [&recvDataLatchB](const FileDescriptor, std::shared_ptr& data) { + auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr& data) { recvDataLatchB.set(data); }; @@ -575,7 +576,7 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const PeerID, std::shared_ptr&) { l.set(); }; @@ -602,7 +603,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) utils::Latch l; ScopedGlibLoop loop; - auto signalHandler = [&l](const FileDescriptor, std::shared_ptr&) { + auto signalHandler = [&l](const PeerID, std::shared_ptr&) { l.set(); }; @@ -614,9 +615,9 @@ BOOST_AUTO_TEST_CASE(ClientGSource) c.setMethodHandler(1, echoCallback); c.setSignalHandler(2, signalHandler); - FileDescriptor peerFD = connectClientGSource(s, c); + PeerID peerID = connectClientGSource(s, c); - testEcho(s, 1, peerFD); + testEcho(s, 1, peerID); auto data = std::make_shared(1); s.signal(2, data); @@ -633,7 +634,7 @@ BOOST_AUTO_TEST_CASE(UsersError) Client c(socketPath); auto clientID = connect(s, c); - auto throwingMethodHandler = [&](const FileDescriptor, std::shared_ptr&) -> std::shared_ptr { + auto throwingMethodHandler = [&](const PeerID, std::shared_ptr&) -> std::shared_ptr { throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE); }; -- 2.7.4