From 70a84ae9b6a4d2f7288cfce840b5b536fa917e2c Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 17 Mar 2015 15:55:16 +0100 Subject: [PATCH 01/16] Possibility to remove ipv4/ipv6 addresses from interface [Feature] Possibility to remove ipv4/ipv6 addresses from interface [Cause] N/A [Solution] Implemented: vsm_netdev_del_ipv4_addr, vsm_netdev_del_ipv6_addr [Verification] Build, run test Change-Id: If1e43c73f443e5480e5f1794a1d1f29fa78c3dd3 --- client/vasum-client-impl.cpp | 38 +++++++++++++++++++++ client/vasum-client-impl.hpp | 16 +++++++++ client/vasum-client.cpp | 18 ++++++++++ client/vasum-client.h | 38 +++++++++++++++++++-- common/api/messages.hpp | 13 ++++++++ server/host-connection.cpp | 14 ++++++++ server/host-connection.hpp | 9 +++++ server/host-dbus-definitions.hpp | 66 ++++++++++++++++++++----------------- server/netdev.cpp | 56 +++++++++++++++++++++++++++++++ server/netdev.hpp | 5 +++ server/zone-admin.cpp | 5 +++ server/zone-admin.hpp | 5 +++ server/zone.cpp | 6 ++++ server/zone.hpp | 5 +++ server/zones-manager.cpp | 20 +++++++++++ server/zones-manager.hpp | 2 ++ tests/unit_tests/server/ut-zone.cpp | 47 +++++++++++++++++++++++--- 17 files changed, 325 insertions(+), 38 deletions(-) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 1de4de0..0c5482a 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -744,6 +744,44 @@ VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* zone, } } +VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* zone, + const char* netdevId, + struct in_addr* addr, + int prefix) noexcept +{ + std::string ip; + try { + //CIDR notation + ip = toString(addr) + "/" + to_string(prefix); + } catch(const std::exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } + + GVariant* args_in = g_variant_new("(sss)", zone, netdevId, ip.c_str()); + return callMethod(HOST_INTERFACE, api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, args_in); +} + +VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* zone, + const char* netdevId, + struct in6_addr* addr, + int prefix) noexcept +{ + + std::string ip; + try { + //CIDR notation + ip = toString(addr) + "/" + to_string(prefix); + } catch(const std::exception& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + return vsm_get_status(); + } + + GVariant* args_in = g_variant_new("(sss)", zone, netdevId, ip.c_str()); + return callMethod(HOST_INTERFACE, api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, args_in); +} + + VsmStatus Client::vsm_netdev_up(const char* zone, const char* netdevId) noexcept { try { diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 1493a00..4e01966 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -235,6 +235,22 @@ public: int prefix) noexcept; /** + * @see ::vsm_netdev_del_ipv4_addr + */ + VsmStatus vsm_netdev_del_ipv4_addr(const char* zone, + const char* netdevId, + struct in_addr* addr, + int prefix) noexcept; + + /** + * @see ::vsm_netdev_del_ipv6_addr + */ + VsmStatus vsm_netdev_del_ipv6_addr(const char* zone, + const char* netdevId, + struct in6_addr* addr, + int prefix) noexcept; + + /** * @see ::vsm_netdev_up */ VsmStatus vsm_netdev_up(const char* zone, const char* netdevId) noexcept; diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 9c0ca60..c12e8c6 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -250,6 +250,24 @@ API VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, return getClient(client).vsm_netdev_set_ipv6_addr(zone, netdevId, addr, prefix); } +API VsmStatus vsm_netdev_del_ipv4_addr(VsmClient client, + const char* zone, + const char* netdevId, + struct in_addr* addr, + int prefix) +{ + return getClient(client).vsm_netdev_del_ipv4_addr(zone, netdevId, addr, prefix); +} + +API VsmStatus vsm_netdev_del_ipv6_addr(VsmClient client, + const char* zone, + const char* netdevId, + struct in6_addr* addr, + int prefix) +{ + return getClient(client).vsm_netdev_del_ipv6_addr(zone, netdevId, addr, prefix); +} + API VsmStatus vsm_netdev_up(VsmClient client, const char* zone, const char* netdevId) diff --git a/client/vasum-client.h b/client/vasum-client.h index 18af990..c252b32 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -552,6 +552,38 @@ VsmStatus vsm_netdev_set_ipv6_addr(VsmClient client, int prefix); /** + * Remove ipv4 address from netdev + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] netdevId network device id + * @param[in] addr ipv4 address + * @param[in] prefix bit-length of the network prefix + * @return status of this function call + */ +VsmStatus vsm_netdev_del_ipv4_addr(VsmClient client, + const char* zone, + const char* netdevId, + struct in_addr* addr, + int prefix); + +/** + * Remove ipv6 address from netdev + * + * @param[in] client vasum-server's client + * @param[in] zone zone name + * @param[in] netdevId network device id + * @param[in] addr ipv6 address + * @param[in] prefix bit-length of the network prefix + * @return status of this function call + */ +VsmStatus vsm_netdev_del_ipv6_addr(VsmClient client, + const char* zone, + const char* netdevId, + struct in6_addr* addr, + int prefix); + +/** * Turn up a network device in the zone * * @param[in] client vasum-server's client @@ -750,9 +782,9 @@ VsmStatus vsm_remove_declaration(VsmClient client, * @param data custom user's data pointer passed to vsm_add_notification_callback() */ typedef void (*VsmNotificationCallback)(const char* zone, - const char* application, - const char* message, - void* data); + const char* application, + const char* message, + void* data); /** * Send message to active zone. * diff --git a/common/api/messages.hpp b/common/api/messages.hpp index a567975..de193bd 100644 --- a/common/api/messages.hpp +++ b/common/api/messages.hpp @@ -146,6 +146,19 @@ struct CreateNetDevMacvlanIn { ) }; +struct DeleteNetdevIpAddressIn { + std::string zone; + std::string netdev; + std::string ip; + + CONFIG_REGISTER + ( + zone, + netdev, + ip + ) +}; + struct DeclareFileIn { std::string zone; int32_t type; diff --git a/server/host-connection.cpp b/server/host-connection.cpp index 993b63d..f3cbfa0 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -167,6 +167,11 @@ void HostConnection::setDestroyNetdevCallback(const DestroyNetdevCallback& callb mDestroyNetdevCallback = callback; } +void HostConnection::setDeleleNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback) +{ + mDeleteNetdevIpAddressCallback = callback; +} + void HostConnection::setDeclareFileCallback(const DeclareFileCallback& callback) { mDeclareFileCallback = callback; @@ -397,6 +402,15 @@ void HostConnection::onMessageCall(const std::string& objectPath, } } + if (methodName == api::host::METHOD_DELETE_NETDEV_IP_ADDRESS) { + api::DeleteNetdevIpAddressIn data; + config::loadFromGVariant(parameters, data); + if (mDeleteNetdevIpAddressCallback) { + auto rb = std::make_shared>(result); + mDeleteNetdevIpAddressCallback(data, rb); + } + } + if (methodName == api::host::METHOD_DECLARE_FILE) { api::DeclareFileIn data; config::loadFromGVariant(parameters, data); diff --git a/server/host-connection.hpp b/server/host-connection.hpp index 4cb1c8e..4ad07c8 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -82,6 +82,9 @@ public: typedef std::function CreateNetdevPhysCallback; + typedef std::function DeleteNetdevIpAddressCallback; typedef std::function DestroyNetdevCallback; @@ -194,6 +197,11 @@ public: void setDestroyNetdevCallback(const DestroyNetdevCallback& callback); /** + * Register a callback called to remove ip address from netdev + */ + void setDeleleNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback); + + /** * Register a callback called to declare file */ void setDeclareFileCallback(const DeclareFileCallback& callback); @@ -291,6 +299,7 @@ private: CreateNetdevMacvlanCallback mCreateNetdevMacvlanCallback; CreateNetdevPhysCallback mCreateNetdevPhysCallback; DestroyNetdevCallback mDestroyNetdevCallback; + DeleteNetdevIpAddressCallback mDeleteNetdevIpAddressCallback; DeclareFileCallback mDeclareFileCallback; DeclareMountCallback mDeclareMountCallback; DeclareLinkCallback mDeclareLinkCallback; diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 2ac5745..1e6fecc 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -32,39 +32,40 @@ namespace vasum { namespace api { namespace host { -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 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_NOT_RUNNING = "org.tizen.vasum.host.Error.ZonesNotRunning"; +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"; -const std::string METHOD_GET_ACTIVE_ZONE_ID = "GetActiveZoneId"; -const std::string METHOD_GET_ZONE_INFO = "GetZoneInfo"; -const std::string METHOD_SET_NETDEV_ATTRS = "SetNetdevAttrs"; -const std::string METHOD_GET_NETDEV_ATTRS = "GetNetdevAttrs"; -const std::string METHOD_GET_NETDEV_LIST = "GetNetdevList"; -const std::string METHOD_CREATE_NETDEV_VETH = "CreateNetdevVeth"; -const std::string METHOD_CREATE_NETDEV_MACVLAN = "CreateNetdevMacvlan"; -const std::string METHOD_CREATE_NETDEV_PHYS = "CreateNetdevPhys"; -const std::string METHOD_DESTROY_NETDEV = "DestroyNetdev"; -const std::string METHOD_DECLARE_FILE = "DeclareFile"; -const std::string METHOD_DECLARE_MOUNT = "DeclareMount"; -const std::string METHOD_DECLARE_LINK = "DeclareLink"; -const std::string METHOD_GET_DECLARATIONS = "GetDeclarations"; -const std::string METHOD_REMOVE_DECLARATION = "RemoveDeclaration"; -const std::string METHOD_SET_ACTIVE_ZONE = "SetActiveZone"; -const std::string METHOD_CREATE_ZONE = "CreateZone"; -const std::string METHOD_DESTROY_ZONE = "DestroyZone"; -const std::string METHOD_SHUTDOWN_ZONE = "ShutdownZone"; -const std::string METHOD_START_ZONE = "StartZone"; -const std::string METHOD_LOCK_ZONE = "LockZone"; -const std::string METHOD_UNLOCK_ZONE = "UnlockZone"; -const std::string METHOD_GRANT_DEVICE = "GrantDevice"; -const std::string METHOD_REVOKE_DEVICE = "RevokeDevice"; +const std::string METHOD_GET_ZONE_DBUSES = "GetZoneDbuses"; +const std::string METHOD_GET_ZONE_ID_LIST = "GetZoneIds"; +const std::string METHOD_GET_ACTIVE_ZONE_ID = "GetActiveZoneId"; +const std::string METHOD_GET_ZONE_INFO = "GetZoneInfo"; +const std::string METHOD_SET_NETDEV_ATTRS = "SetNetdevAttrs"; +const std::string METHOD_GET_NETDEV_ATTRS = "GetNetdevAttrs"; +const std::string METHOD_GET_NETDEV_LIST = "GetNetdevList"; +const std::string METHOD_CREATE_NETDEV_VETH = "CreateNetdevVeth"; +const std::string METHOD_CREATE_NETDEV_MACVLAN = "CreateNetdevMacvlan"; +const std::string METHOD_CREATE_NETDEV_PHYS = "CreateNetdevPhys"; +const std::string METHOD_DESTROY_NETDEV = "DestroyNetdev"; +const std::string METHOD_DELETE_NETDEV_IP_ADDRESS = "DeleteNetdevIpAddress"; +const std::string METHOD_DECLARE_FILE = "DeclareFile"; +const std::string METHOD_DECLARE_MOUNT = "DeclareMount"; +const std::string METHOD_DECLARE_LINK = "DeclareLink"; +const std::string METHOD_GET_DECLARATIONS = "GetDeclarations"; +const std::string METHOD_REMOVE_DECLARATION = "RemoveDeclaration"; +const std::string METHOD_SET_ACTIVE_ZONE = "SetActiveZone"; +const std::string METHOD_CREATE_ZONE = "CreateZone"; +const std::string METHOD_DESTROY_ZONE = "DestroyZone"; +const std::string METHOD_SHUTDOWN_ZONE = "ShutdownZone"; +const std::string METHOD_START_ZONE = "StartZone"; +const std::string METHOD_LOCK_ZONE = "LockZone"; +const std::string METHOD_UNLOCK_ZONE = "UnlockZone"; +const std::string METHOD_GRANT_DEVICE = "GrantDevice"; +const std::string METHOD_REVOKE_DEVICE = "RevokeDevice"; -const std::string SIGNAL_ZONE_DBUS_STATE = "ZoneDbusState"; +const std::string SIGNAL_ZONE_DBUS_STATE = "ZoneDbusState"; const std::string DEFINITION = @@ -125,6 +126,11 @@ const std::string DEFINITION = " " " " " " + " " + " " + " " + " " + " " " " " " " " diff --git a/server/netdev.cpp b/server/netdev.cpp index da58641..38ccb88 100644 --- a/server/netdev.cpp +++ b/server/netdev.cpp @@ -120,6 +120,11 @@ uint32_t getInterfaceIndex(const string& name, pid_t nsPid) { return infoPeer.ifi_index; } +int getIpFamily(const std::string& ip) +{ + return ip.find(':') == std::string::npos ? AF_INET : AF_INET6; +} + void validateNetdevName(const string& name) { if (name.size() <= 1 || name.size() >= IFNAMSIZ) { @@ -331,6 +336,36 @@ void setIpAddresses(const pid_t nsPid, send(nlm, nsPid); } +void deleteIpAddress(const pid_t nsPid, + const uint32_t index, + const std::string& ip, + int prefixlen, + int family) +{ + NetlinkMessage nlm(RTM_DELADDR, NLM_F_REQUEST | NLM_F_ACK); + ifaddrmsg infoAddr = utils::make_clean(); + infoAddr.ifa_family = family; + infoAddr.ifa_index = index; + infoAddr.ifa_prefixlen = prefixlen; + nlm.put(infoAddr); + if (family == AF_INET6) { + in6_addr addr6; + if (inet_pton(AF_INET6, ip.c_str(), &addr6) != 1) { + throw VasumException("Can't delete ipv6 address"); + }; + nlm.put(IFA_ADDRESS, addr6); + nlm.put(IFA_LOCAL, addr6); + } else { + assert(family == AF_INET); + in_addr addr4; + if (inet_pton(AF_INET, ip.c_str(), &addr4) != 1) { + throw VasumException("Can't delete ipv4 address"); + }; + nlm.put(IFA_LOCAL, addr4); + } + send(nlm, nsPid); +} + } // namespace void createVeth(const pid_t& nsPid, const string& nsDev, const string& hostDev) @@ -565,6 +600,27 @@ void setAttrs(const pid_t nsPid, const std::string& netdev, const Attrs& attrs) setIp(ipv6, infoPeer.ifi_index, AF_INET6); } +void deleteIpAddress(const pid_t nsPid, + const std::string& netdev, + const std::string& ip) +{ + uint32_t index = getInterfaceIndex(netdev, nsPid); + size_t slash = ip.find('/'); + if (slash == string::npos) { + LOGE("Wrong address format: it is not CIDR notation: can't find '/'"); + throw VasumException("Wrong address format"); + } + int prefixlen = 0; + try { + prefixlen = stoi(ip.substr(slash + 1)); + } catch (const std::exception& ex) { + LOGE("Wrong address format: invalid prefixlen"); + throw VasumException("Wrong address format: invalid prefixlen"); + } + deleteIpAddress(nsPid, index, ip.substr(0, slash), prefixlen, getIpFamily(ip)); +} + + } //namespace netdev } //namespace vasum diff --git a/server/netdev.hpp b/server/netdev.hpp index 5e5821d..b3c574d 100644 --- a/server/netdev.hpp +++ b/server/netdev.hpp @@ -57,6 +57,11 @@ void createBridge(const std::string& netdev); Attrs getAttrs(const pid_t nsPid, const std::string& netdev); void setAttrs(const pid_t nsPid, const std::string& netdev, const Attrs& attrs); +/** + * Remove ipv4/ipv6 address from interface + */ +void deleteIpAddress(const pid_t nsPid, const std::string& netdev, const std::string& ip); + } //namespace netdev } //namespace vasum diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index b584279..3098f29 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -322,4 +322,9 @@ std::vector ZoneAdmin::getNetdevList() return netdev::listNetdev(mZone.getInitPid()); } +void ZoneAdmin::deleteNetdevIpAddress(const std::string& netdev, const std::string& ip) +{ + netdev::deleteIpAddress(mZone.getInitPid(), netdev, ip); +} + } // namespace vasum diff --git a/server/zone-admin.hpp b/server/zone-admin.hpp index db2b0f2..d1b179d 100644 --- a/server/zone-admin.hpp +++ b/server/zone-admin.hpp @@ -169,6 +169,11 @@ public: */ std::vector getNetdevList(); + /** + * Remove ipv4/ipv6 address from network device + */ + void deleteNetdevIpAddress(const std::string& netdev, const std::string& ip); + private: const ZoneConfig& mConfig; const ZoneDynamicConfig& mDynamicConfig; diff --git a/server/zone.cpp b/server/zone.cpp index b0c3c28..e26da52 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -513,4 +513,10 @@ std::vector Zone::getNetdevList() return mAdmin->getNetdevList(); } +void Zone::deleteNetdevIpAddress(const std::string& netdev, const std::string& ip) +{ + Lock lock(mReconnectMutex); + mAdmin->deleteNetdevIpAddress(netdev, ip); +} + } // namespace vasum diff --git a/server/zone.hpp b/server/zone.hpp index b981e9a..687077f 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -311,6 +311,11 @@ public: */ std::vector getNetdevList(); + /** + * Remove ipv4/ipv6 address from network device + */ + void deleteNetdevIpAddress(const std::string& netdev, const std::string& ip); + private: utils::Worker::Pointer mWorker; ZoneConfig mConfig; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 67e2b88..4f34a76 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -163,6 +163,9 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setDestroyNetdevCallback(bind(&ZonesManager::handleDestroyNetdevCall, this, _1, _2)); + mHostConnection.setDeleleNetdevIpAddressCallback(bind(&ZonesManager::handleDeleteNetdevIpAddressCall, + this, _1, _2)); + mHostConnection.setDeclareFileCallback(bind(&ZonesManager::handleDeclareFileCall, this, _1, _2)); @@ -945,6 +948,23 @@ void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data, } } +void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data, + api::MethodResultBuilder::Pointer result) +{ + LOGI("DelNetdevIpAddress call"); + try { + Lock lock(mMutex); + getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const VasumException& ex) { + LOGE("Can't delete address: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } +} + void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data, api::MethodResultBuilder::Pointer result) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index ae89566..f789595 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -187,6 +187,8 @@ private: api::MethodResultBuilder::Pointer result); void handleDestroyNetdevCall(const api::DestroyNetDevIn& data, api::MethodResultBuilder::Pointer result); + void handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data, + api::MethodResultBuilder::Pointer result); void handleDeclareFileCall(const api::DeclareFileIn& data, api::MethodResultBuilder::Pointer result); void handleDeclareMountCall(const api::DeclareMountIn& data, diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index 722f32c..dc66753 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(DbusConnection) c->stop(true); } -// TODO: DbusReconnectionTest +// TODO: DbusReconnection BOOST_AUTO_TEST_CASE(ListNetdev) { @@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(CreateNetdevMacvlan) BOOST_CHECK(find(netdevs.begin(), netdevs.end(), ZONE_NETDEV) != netdevs.end()); } -BOOST_AUTO_TEST_CASE(GetNetdevAttrsTest) +BOOST_AUTO_TEST_CASE(GetNetdevAttrs) { setupBridge(BRIDGE_NAME); auto c = create(TEST_CONFIG_PATH); @@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE(GetNetdevAttrsTest) BOOST_CHECK(gotType); } -BOOST_AUTO_TEST_CASE(SetNetdevAttrsTest) +BOOST_AUTO_TEST_CASE(SetNetdevAttrs) { setupBridge(BRIDGE_NAME); auto c = create(TEST_CONFIG_PATH); @@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE(SetNetdevAttrsTest) WhatEquals("Unsupported attribute: does_not_exists")); } -BOOST_AUTO_TEST_CASE(SetNetdevIpv4Test) +BOOST_AUTO_TEST_CASE(SetNetdevIpv4) { setupBridge(BRIDGE_NAME); auto c = create(TEST_CONFIG_PATH); @@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(SetNetdevIpv4Test) BOOST_CHECK_EQUAL(gotIp, 3); } -BOOST_AUTO_TEST_CASE(SetNetdevIpv6Test) +BOOST_AUTO_TEST_CASE(SetNetdevIpv6) { setupBridge(BRIDGE_NAME); auto c = create(TEST_CONFIG_PATH); @@ -349,4 +349,41 @@ BOOST_AUTO_TEST_CASE(SetNetdevIpv6Test) BOOST_CHECK_EQUAL(gotIp, 3); } +BOOST_AUTO_TEST_CASE(DelNetdevIpAddress) +{ + auto contain = [](const ZoneAdmin::NetdevAttrs& container, const std::string& key) { + return container.end() != find_if(container.begin(), + container.end(), + [&](const ZoneAdmin::NetdevAttrs::value_type& value) { + return std::get<0>(value) == key; + }); + }; + + setupBridge(BRIDGE_NAME); + auto c = create(TEST_CONFIG_PATH); + c->start(); + ensureStarted(); + c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); + ZoneAdmin::NetdevAttrs attrs; + attrs.push_back(std::make_tuple("ipv6", "ip:2001:db8::1,prefixlen:64")); + attrs.push_back(std::make_tuple("ipv4", "ip:192.168.4.1,prefixlen:24")); + c->setNetdevAttrs(ZONE_NETDEV, attrs); + attrs = c->getNetdevAttrs(ZONE_NETDEV); + BOOST_REQUIRE(contain(attrs, "ipv4")); + BOOST_REQUIRE(contain(attrs, "ipv6")); + + c->deleteNetdevIpAddress(ZONE_NETDEV, "192.168.4.1/24"); + attrs = c->getNetdevAttrs(ZONE_NETDEV); + BOOST_CHECK(!contain(attrs, "ipv4")); + BOOST_CHECK(contain(attrs, "ipv6")); + + c->deleteNetdevIpAddress(ZONE_NETDEV, "2001:db8::1/64"); + attrs = c->getNetdevAttrs(ZONE_NETDEV); + BOOST_REQUIRE(!contain(attrs, "ipv4")); + BOOST_REQUIRE(!contain(attrs, "ipv6")); + + BOOST_CHECK_THROW(c->deleteNetdevIpAddress(ZONE_NETDEV, "192.168.4.1/24"), VasumException); + BOOST_CHECK_THROW(c->deleteNetdevIpAddress(ZONE_NETDEV, "2001:db8::1/64"), VasumException); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 04fbbc8a8324a2025d268d83036fbd39092f0438 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 25 Mar 2015 16:22:29 +0100 Subject: [PATCH 02/16] Added netdev_down to cli and made some code cleanup (cli/client) [Bug/Feature] Added netdev_down to cli and made some code cleanup (cli/client) [Cause] N/A [Solution] N/A [Verification] Create netdev, turn it up and turn it down Change-Id: I698de7ccd181d0d8adbb892facddb5d552d6aee4 --- cli/main.cpp | 31 ++++++++++++++++++++----------- client/vasum-client-impl.cpp | 8 ++++---- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/cli/main.cpp b/cli/main.cpp index 2431313..6c10945 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -145,40 +145,40 @@ std::map commands = { { "create_netdev_veth", { create_netdev_veth, - "create_netdev_veth zone_id zoneDev hostDev", + "create_netdev_veth zone_id zone_netdev_id host_netdev_id", "Create netdev in zone", {{"zone_id", "id zone name"}, - {"zoneDev", "network device id"}, - {"hostDev", "host bridge id"}} + {"zone_netdev_id", "network device id"}, + {"host_netdev_id", "host bridge id"}} } }, { "create_netdev_macvlan", { create_netdev_macvlan, - "create_netdev_macvlan zone_id zoneDev hostDev mode", + "create_netdev_macvlan zone_id zone_netdev_id host_netdev_id mode", "Create netdev in zone", {{"zone_id", "id zone name"}, - {"zoneDev", "network device id"}, - {"hostDev", "host bridge id"}, + {"zone_netdev_id", "network device id"}, + {"host_netdev_id", "host bridge id"}, {"mode", "macvlan mode (private, vepa, bridge, passthru)"}} } }, { "create_netdev_phys", { create_netdev_phys, - "create_netdev_phys zone_id devId", + "create_netdev_phys zone_id netdev_id", "Create/move netdev to zone", {{"zone_id", "id zone name"}, - {"devId", "network device id"}} + {"netdev_id", "network device name"}} } }, { "lookup_netdev_by_name", { lookup_netdev_by_name, - "lookup_netdev_by_name zone_id devId", + "lookup_netdev_by_name zone_id netdev_id", "Get netdev flags", {{"zone_id", "id zone name"}, - {"devId", "network device id"}} + {"netdev_id", "network device name"}} } }, { @@ -187,7 +187,7 @@ std::map commands = { "destroy_netdev zone_id devId", "Destroy netdev in zone", {{"zone_id", "id zone name"}, - {"devId", "network device id"}} + {"netdev_id", "network device name"}} } }, { @@ -248,6 +248,15 @@ std::map commands = { } }, { + "netdev_down", { + netdev_down, + "netdev_down zone_id netdev_id", + "Turn down a network device in the zone", + {{"zone_id", "id zone name"}, + {"netdev_id", "network device id"}} + } + }, + { "zone_get_netdevs", { zone_get_netdevs, "zone_get_netdevs zone_id", diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 0c5482a..f4d8580 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -713,12 +713,12 @@ VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* zone, VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* zone, const char* netdevId, struct in_addr* addr, - int mask) noexcept + int prefix) noexcept { try { GVariant* dict = createTupleArray({make_tuple("ipv4", "ip:" + toString(addr) + "," - "prefixlen:" + to_string(mask))}); + "prefixlen:" + to_string(prefix))}); GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); } catch (exception& ex) { @@ -730,12 +730,12 @@ VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* zone, VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* zone, const char* netdevId, struct in6_addr* addr, - int mask) noexcept + int prefix) noexcept { try { GVariant* dict = createTupleArray({make_tuple("ipv6", "ip:" + toString(addr) + "," - "prefixlen:" + to_string(mask))}); + "prefixlen:" + to_string(prefix))}); GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); } catch (exception& ex) { -- 2.7.4 From 1161465dffe73552e9996c9934ae73b285f2493b Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 30 Mar 2015 15:37:40 +0200 Subject: [PATCH 03/16] FIX: vsm_lookup_zone_by_id, vsm_zone_get_netdevs; test added [BUG] Can't get return parameters from vsm_lookup_zone_by_id. Segfault when calling zone_get_netdevs. [Cause] Return type should by (siss) not ((siss)); parameters aren't set properly. Wrong return type in vsm_zone_get_netdevs (NetDevList instead GetNetDevAttrs). [Solution] Return type changed. Added ClientSuite/LookupZoneById, ClientSuite/ZoneGetNetdevs tests. [Verification] Run ClientSuite test Change-Id: I56365571aef20ecf445b5a89b6edf94abd567a35 --- client/vasum-client-impl.cpp | 7 ++---- server/host-connection.cpp | 2 +- server/host-dbus-definitions.hpp | 5 +++- server/zones-manager.cpp | 3 +++ tests/unit_tests/client/ut-client.cpp | 43 +++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index f4d8580..4f3a05c 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -491,15 +491,12 @@ VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept VsmStatus ret = callMethod(HOST_INTERFACE, api::host::METHOD_GET_ZONE_INFO, args_in, - "((siss))", + "(siss)", &out); if (ret != VSMCLIENT_SUCCESS) { return ret; } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toBasic(unpacked, zone); - g_variant_unref(unpacked); + toBasic(out, zone); g_variant_unref(out); return ret; } diff --git a/server/host-connection.cpp b/server/host-connection.cpp index f3cbfa0..1bdd790 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -355,7 +355,7 @@ void HostConnection::onMessageCall(const std::string& objectPath, config::loadFromGVariant(parameters, data); if (mGetNetdevListCallback) { - auto rb = std::make_shared>(result); + auto rb = std::make_shared>(result); mGetNetdevListCallback(data, rb); } return; diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 1e6fecc..7476bb5 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -91,7 +91,10 @@ const std::string DEFINITION = " " " " " " - " " + " " + " " + " " + " " " " " " " " diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 4f34a76..d3e802b 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -810,6 +810,9 @@ void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId, return; } + zoneInfo->id = zone.getId(); + zoneInfo->vt = zone.getVT(); + zoneInfo->rootPath = zone.getRootPath(); result->set(zoneInfo); } diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 197da5e..40372f4 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -221,6 +221,26 @@ BOOST_AUTO_TEST_CASE(GetActiveZoneId) vsm_client_free(client); } +BOOST_AUTO_TEST_CASE(LookupZoneById) +{ + const std::string activeZoneId = "zone1"; + + VsmClient client = vsm_client_create(); + VsmStatus status = vsm_connect(client); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); + VsmZone info; + status = vsm_lookup_zone_by_id(client, activeZoneId.c_str(), &info); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); + + BOOST_CHECK_EQUAL(info->id, activeZoneId); + BOOST_CHECK_EQUAL(info->state, RUNNING); + BOOST_CHECK_EQUAL(info->terminal, -1); + BOOST_CHECK_EQUAL(info->rootfs_path, "/tmp/ut-zones/" + activeZoneId + "/rootfs"); + + vsm_zone_free(info); + vsm_client_free(client); +} + BOOST_AUTO_TEST_CASE(SetActiveZone) { const std::string newActiveZoneId = "zone2"; @@ -425,4 +445,27 @@ BOOST_AUTO_TEST_CASE(Provision) vsm_client_free(client); } +BOOST_AUTO_TEST_CASE(ZoneGetNetdevs) +{ + const std::string activeZoneId = "zone1"; + + VsmClient client = vsm_client_create(); + VsmStatus status = vsm_connect(client); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); + VsmArrayString netdevs; + status = vsm_zone_get_netdevs(client, activeZoneId.c_str(), &netdevs); + BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); + BOOST_REQUIRE(netdevs != NULL); + vsm_array_string_free(netdevs); + vsm_client_free(client); +} + +//TODO: We need createBridge from vasum::netdev +//BOOST_AUTO_TEST_CASE(CreateDestroyNetdev) +//BOOST_AUTO_TEST_CASE(LookupNetdev) +//BOOST_AUTO_TEST_CASE(GetSetDeleteIpAddr) +//BOOST_AUTO_TEST_CASE(NetdevUpDown) + + + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 2c75d62ba8dd17cbc33a159451d9b86c2109e4dc Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Mon, 16 Feb 2015 19:43:29 +0100 Subject: [PATCH 04/16] Cleaned integration tests, load daemon.conf as json [Bug/Feature] Integration tests neglected, fix launchProc [Cause] tests outdated [Solution] update test scripts [Verification] Build, install, run integrataion tests Change-Id: I4c911d7e7842e96e0fe0716ecab0b03331032f06 --- tests/integration_tests/common/vsm_test_utils.py | 7 +- .../image_tests/config_checker.py | 77 +-------- .../network_tests/network_common.py | 188 +++------------------ .../network_tests/network_tests.py | 17 +- 4 files changed, 39 insertions(+), 250 deletions(-) diff --git a/tests/integration_tests/common/vsm_test_utils.py b/tests/integration_tests/common/vsm_test_utils.py index bb84f99..30e0ac8 100644 --- a/tests/integration_tests/common/vsm_test_utils.py +++ b/tests/integration_tests/common/vsm_test_utils.py @@ -5,7 +5,6 @@ import subprocess import os - def launchProc(cmd): '''! Launch specified command as a subprocess. @@ -13,12 +12,12 @@ def launchProc(cmd): stderr. @param cmd Command to be launched - @return Tuple containing output provided by specified command and return code. + @return Tuple containing subprocess exit code and text output received ''' p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - ret = p.wait() + rc = p.wait() output = p.stdout.read() - return (output, ret) + return (rc,output) def mount(dir, opts=[]): diff --git a/tests/integration_tests/image_tests/config_checker.py b/tests/integration_tests/image_tests/config_checker.py index 0d47b8e..ce16403 100644 --- a/tests/integration_tests/image_tests/config_checker.py +++ b/tests/integration_tests/image_tests/config_checker.py @@ -14,76 +14,13 @@ class ConfigChecker: zones existing in the system (name and rootfs path). ''' - def __parseLibvirtXML(self, path): - '''! Parses libvirt's configuration in order to extract zone name and path. + def __init__(self, confpath): + print "ConfigChecker", confpath + with open(confpath) as jf: + self.conf = json.load(jf) - @param path Libvirt's zone configuration path - ''' - tree = ET.parse(path) - root = tree.getroot() - name = root.find("name").text - rootFound = False + # TODO: extract data for tests from json object - # extract directory mountings - for elem in root.iterfind('devices/filesystem'): - if "type" not in elem.attrib: - raise Exception("'type' attribute not found for 'filesystem' node in file: " + path) - - nodeSource = elem.find("source") - if nodeSource is None: - raise Exception("'source' not found in 'filesystem' node in file: " + path) - - nodeTarget = elem.find("target") - if nodeTarget is None: - raise Exception("'target' not found in 'filesystem' node in file: " + path) - - source = nodeSource.attrib["dir"] - target = nodeTarget.attrib["dir"] - if target == "/": - if rootFound: - raise Exception("Multiple root fs mounts found in file: " + path) - else: - self.zones[name] = source - print " Zone '" + name + "' found at: " + source - rootFound = True - - if not rootFound: - raise Exception("Root directory of '" + name + "' zone not specified in XML") - - def __init__(self, mainConfigPath): - '''! Parses daemon's JSON configuration files. - - @param mainConfigPath Path to the main config "daemon.conf" - ''' self.zones = {} - print "Looking for zone IDs..." - - # load main daemon JSON config file - if not os.path.isfile(mainConfigPath): - raise Exception(mainConfigPath + " not found. " + - "Please verify that vasum is properly installed.") - with open(mainConfigPath) as daemonConfigStr: - daemonConfigData = json.load(daemonConfigStr) - daemonConfigDir = os.path.dirname(os.path.abspath(mainConfigPath)) - - # get dictionary with zones - zoneConfigPaths = daemonConfigData["zoneConfigs"] - for configPath in zoneConfigPaths: - - # open zone config file - zoneConfigPath = os.path.join(daemonConfigDir, configPath) - if not os.path.isfile(zoneConfigPath): - raise Exception(zoneConfigPath + " not found. " + - "Please verify that vasum is properly installed.") - with open(zoneConfigPath) as zoneConfigStr: - zoneConfigData = json.load(zoneConfigStr) - - # extract XML config path for libvirt - libvirtConfigPath = os.path.join(daemonConfigDir, "zones", - zoneConfigData["config"]) - - output, ret = vsm_test_utils.launchProc("virt-xml-validate " + libvirtConfigPath) - if ret == 0: - self.__parseLibvirtXML(libvirtConfigPath) - else: - raise Exception(output) + #TODO prepate zones config into list of (zone_name,zone_roofs_path) + # self.conf["zoneConfigs"] -> (zone, self.conf["zonesPath"]+"/"+zone) diff --git a/tests/integration_tests/network_tests/network_common.py b/tests/integration_tests/network_tests/network_common.py index 945b255..acb120c 100755 --- a/tests/integration_tests/network_tests/network_common.py +++ b/tests/integration_tests/network_tests/network_common.py @@ -21,6 +21,7 @@ import subprocess import string import sys import os +import traceback # Debug command on/off DEBUG_COMMAND=False @@ -28,18 +29,18 @@ DEBUG_COMMAND=False # Test urls TEST_URL_INTERNET=["www.samsung.com", "www.google.com", "www.oracle.com"] +#TODO read path from config (daemon.conf) # Path to test zone -TEST_ZONE_PATH="/opt/usr/zones/private" +TEST_ZONE_PATH="/usr/share/.zones" # Device Ethernet device ETHERNET_DEVICE="usb0" ETHERNET_DEVICE_DETECT=False # Test zones -ZONE_T1="business" -ZONE_T2="private" - -zones=[ZONE_T1, ZONE_T2] +TEST_ZONE="test" +TEST_ZONE_ROOTFS=TEST_ZONE_PATH+"/"+TEST_ZONE +ZONES=[ TEST_ZONE ] # Null device OUTPUT_TO_NULL_DEVICE=" >/dev/null 2>&1 " @@ -47,18 +48,25 @@ OUTPUT_TO_NULL_DEVICE=" >/dev/null 2>&1 " # Ping timeout PING_TIME_OUT=3 -# The calss store test cases results -class TestNetworkInfo: +# The class store test cases results +class TestInfo: testName = "" - testItemType = [] - testItemName = [] - testItemStatus = [] - testItemResult = [] - testItemDescription = [] + testItems = [] def __init__(self, tn): self.testName = tn +class TestItem: + itype = "" + name = "" + description = "" + status = 0 + result = "" + + def __init__(self, tn, n): + self.itype = tn + self.name = n + # ---------------------------------------------------------- # Functions print info/error/warning message # @@ -95,7 +103,9 @@ def runCommand(cmd, blockDebug=False): rc=0 try: out=vsm_test_utils.launchProc(run_cmd) + rc=out[0] except Exception: + traceback.print_exc() rc=1 if(DEBUG_COMMAND and not blockDebug): @@ -125,10 +135,10 @@ def runCommandAndReadOutput(cmd): break # ---------------------------------------------------------- -# The function checks whether test zone image is present in system +# The function checks whether zone path is present in system # -def test_guest_image(): - rc = runCommand("/usr/bin/chroot " + TEST_ZONE_PATH + " /bin/true") +def test_zone_path(): + rc = runCommand("ls " + TEST_ZONE_PATH) if( rc != 0 ): return 1 return 0 @@ -147,151 +157,3 @@ def getActiveEthernetDevice(): return 0 -# ---------------------------------------------------------- -# The function checks whether mandatory tools are present in -# the system -# -def test_mandatory_toos(): - - tools =["/usr/bin/ping"] - root_tools=[TEST_ZONE_PATH] - - for i in range(len(tools)): - rc = runCommand("/usr/bin/ls " + root_tools[i] + tools[i]) - if( rc != 0 ): - if( root_tools[i] != "" ): - LOG_ERROR("No " + tools[i] + " command in guest") - else: - LOG_ERROR("No " + tools[i] + " command in host") - return 1 - return 0 - -def virshCmd(args): - return runCommand("/usr/bin/virsh -c lxc:/// " + args) - -# ---------------------------------------------------------- -# The function tests single test case result -# -def test_result(expected_result, result): - if((expected_result >= 0 and result == expected_result) or (expected_result < 0 and result != 0)): - return 0 - return 1 - -# ---------------------------------------------------------- -# The function performs single internet access test -# -def internetAccessTest(zone): - count=0 - for item in TEST_URL_INTERNET: - LOG_INFO(" Test for URL : " + item); - rc = virshCmd("lxc-enter-namespace " + zone + \ - " --noseclabel -- /usr/bin/ping -c 3 -W " + \ - str(PING_TIME_OUT) + " " + item) - if(rc != 0): - count = count + 1 - - if(count != 0): - return 1 - - return 0; - -# ---------------------------------------------------------- -# The function performs single internet access test -# -def networkVisibiltyTest(zone, dest_ip): - return virshCmd("lxc-enter-namespace " + zone + \ - " --noseclabel -- /usr/bin/ping -c 3 -W " + \ - str(PING_TIME_OUT) + " " + dest_ip) - -def printInternetAccessTestStatus(zone, testInfo1): - - text = " Internet access for zone: " + zone + \ - "; TCS = " + testInfo1.testItemResult[len(testInfo1.testItemResult)-1] - - if(testInfo1.testItemResult[len(testInfo1.testItemResult)-1] == "Success"): - LOG_INFO(text) - else: - LOG_ERROR(text) - -def networkVisibiltyTestStatus(src, dest, ip, testInfo2): - - text = " Zone access: " + src + \ - " -> " + dest + \ - " [" + ip + "]" + \ - "; TCS = " + testInfo2.testItemResult[len(testInfo2.testItemResult)-1] - - if(testInfo2.testItemResult[len(testInfo2.testItemResult)-1] == "Success"): - LOG_INFO(text) - else: - LOG_ERROR(text) - -# ---------------------------------------------------------- -# The function performs test case for two zones - Business and Private. -# Both zones are mutually isolated and have access to the Internet. -# -def twoNetworks(): - ltestInfo = TestNetworkInfo("Two networks tests") - - # 0. Test data - zones_list = [ZONE_T1, ZONE_T2] - dest_zones_list = [ZONE_T2, ZONE_T1] - test_ip_list = [["10.0.101.2"], ["10.0.102.2"]] - test_1_expected_res = [ 0, 0] - test_2_expected_res = [-1, -1] - - # 1. Enable internet access for both networks - LOG_INFO(" - Setup device") - - # 2. Internet access - LOG_INFO(" - Two zones environment network test case execution") - LOG_INFO(" - Internet access test") - for i in range(len(zones_list)): - - # - Test case info - ltestInfo.testItemType.append("[Two nets] Internet access") - ltestInfo.testItemName.append(zones_list[i]) - ltestInfo.testItemDescription.append("Internet access test for : " + zones_list[i]) - - # - Perform test - rc = internetAccessTest(zones_list[i]) - - # - Test status store - if(test_result(test_1_expected_res[i], rc) == 0): - ltestInfo.testItemStatus.append(0) - ltestInfo.testItemResult.append("Success") - else: - ltestInfo.testItemStatus.append(1) - ltestInfo.testItemResult.append("Error") - - # - Print status - printInternetAccessTestStatus(zones_list[i], ltestInfo) - - # 3. Mutual zones visibility - LOG_INFO(" - Zones isolation") - for i in range(len(zones_list)): - # Interate over destynation ips - dest_ips = test_ip_list[i] - - for j in range(len(dest_ips)): - # - Test case info - ltestInfo.testItemType.append("[Two nets] Visibility") - ltestInfo.testItemName.append(zones_list[i] + "->" + dest_zones_list[i]) - ltestInfo.testItemDescription.append("Zone access for : " + zones_list[i]) - - # Perform test - rc = networkVisibiltyTest(zones_list[i], dest_ips[j]) - - # - Test status store - if(test_result(test_2_expected_res[i], rc) == 0): - ltestInfo.testItemStatus.append(0) - ltestInfo.testItemResult.append("Success") - else: - ltestInfo.testItemStatus.append(1) - ltestInfo.testItemResult.append("Error") - - # - Print status - networkVisibiltyTestStatus(zones_list[i], dest_zones_list[i], dest_ips[j], ltestInfo) - - LOG_INFO(" - Clean environment") - - return ltestInfo diff --git a/tests/integration_tests/network_tests/network_tests.py b/tests/integration_tests/network_tests/network_tests.py index 980830e..f5fe734 100644 --- a/tests/integration_tests/network_tests/network_tests.py +++ b/tests/integration_tests/network_tests/network_tests.py @@ -35,17 +35,12 @@ class NetworkTestCase(unittest.TestCase): self.assertTrue(False, "ROOT user is required to run the test") return - # 2. Test zone images - if(test_guest_image() == 1): - self.assertTrue(False, "No test zone in path :" + TEST_ZONE_PATH) + # 2. Test zone path + if(test_zone_path() == 1): + self.assertTrue(False, "No test zone path :" + TEST_ZONE_PATH) return - # 3. Test mandatory tools - if(test_mandatory_toos() == 1): - self.assertTrue(False, "No mandatory tools on host or in guest") - return - - # 4. Ethernet device obtaning + # 3. Ethernet device obtaning if(ETHERNET_DEVICE_DETECT and getActiveEthernetDevice() == 1): self.assertTrue(False, "Cannot obtain ethernet device") return @@ -53,10 +48,6 @@ class NetworkTestCase(unittest.TestCase): def test_01twoNetworks(self): '''! Checks networks configuration ''' - print("\n") - ret=twoNetworks() - for item in ret.testItemStatus: - self.assertTrue(item == 0) def main(): unittest.main(verbosity=2) -- 2.7.4 From d14412064cb787309d2a91c77025ae7e1e025b4e Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 7 Apr 2015 08:25:21 +0200 Subject: [PATCH 05/16] Move shutdown timeout to Zone config [Feature] Shutdown timeout is moved to Zone configuration file [Cause] Shutdown timeout was a constant hardcoded into Zone Admin [Solution] Move timeout for shutdown to Zone config file [Verification] Build, install, run tests Change-Id: Ie8dd1f81d6fd21d7685923c31361a86dde5c9a3d --- server/configs/templates/default.conf | 1 + server/zone-admin.cpp | 9 +-------- server/zone-config.hpp | 11 ++++++++++- .../client/configs/ut-client/templates/console-dbus.conf.in | 1 + .../server/configs/ut-server/templates/default.conf | 1 + .../server/configs/ut-zone-admin/templates/buggy.conf | 1 + .../server/configs/ut-zone-admin/templates/missing.conf | 1 + .../configs/ut-zone-admin/templates/test-no-shutdown.conf | 1 + .../server/configs/ut-zone-admin/templates/test.conf | 1 + tests/unit_tests/server/configs/ut-zone/templates/buggy.conf | 1 + .../server/configs/ut-zone/templates/test-dbus.conf.in | 1 + tests/unit_tests/server/configs/ut-zone/templates/test.conf | 1 + .../configs/ut-zones-manager/templates/console-dbus.conf.in | 1 + .../server/configs/ut-zones-manager/templates/console.conf | 1 + 14 files changed, 23 insertions(+), 9 deletions(-) diff --git a/server/configs/templates/default.conf b/server/configs/templates/default.conf index 42f587b..697be47 100644 --- a/server/configs/templates/default.conf +++ b/server/configs/templates/default.conf @@ -8,6 +8,7 @@ "cpuQuotaBackground" : 1000, "privilege" : 10, "vt" : 0, + "shutdownTimeout" : 10, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "runMountPoint" : "~NAME~/run", diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp index 3098f29..0f831d7 100644 --- a/server/zone-admin.cpp +++ b/server/zone-admin.cpp @@ -41,13 +41,6 @@ namespace vasum { -namespace { - -// TODO: this should be in zone's configuration file -const int SHUTDOWN_WAIT = 10; - -} // namespace - const std::uint64_t DEFAULT_CPU_SHARES = 1024; const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000; @@ -163,7 +156,7 @@ void ZoneAdmin::stop() return; } - if (!mZone.shutdown(SHUTDOWN_WAIT)) { + if (!mZone.shutdown(mConfig.shutdownTimeout)) { // force stop if (!mZone.stop()) { throw ZoneOperationException("Could not stop zone"); diff --git a/server/zone-config.hpp b/server/zone-config.hpp index f5d81e5..8d92800 100644 --- a/server/zone-config.hpp +++ b/server/zone-config.hpp @@ -92,6 +92,14 @@ struct ZoneConfig { */ std::vector validLinkPrefixes; + /** + * Timeout in seconds for zone to gracefully shut down. + * After given time, if Zone is not off, forced shutdown occurs. + * + * To wait forever, set -1 timeout. To skip waiting, set 0 timeout. + */ + int shutdownTimeout; + CONFIG_REGISTER ( lxcTemplate, @@ -103,7 +111,8 @@ struct ZoneConfig { cpuQuotaBackground, permittedToSend, // TODO move to dynamic and add an API to change permittedToRecv, // TODO move to dynamic and add an API to change - validLinkPrefixes + validLinkPrefixes, + shutdownTimeout ) }; diff --git a/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in index 7778208..7df03e4 100644 --- a/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in +++ b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in @@ -10,6 +10,7 @@ "enableDbusIntegration" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "/tmp/ut-run/~NAME~", "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], diff --git a/tests/unit_tests/server/configs/ut-server/templates/default.conf b/tests/unit_tests/server/configs/ut-server/templates/default.conf index a2f703e..b637d72 100644 --- a/tests/unit_tests/server/configs/ut-server/templates/default.conf +++ b/tests/unit_tests/server/configs/ut-server/templates/default.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf index f585ae8..c40ab33 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf index a3f305b..99e893d 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf index 98e95ab..363c7df 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf index a16b3fa..df787df 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf index 79436c0..91a9f7f 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in index 5d76429..7d71f2d 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in @@ -10,6 +10,7 @@ "enableDbusIntegration" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "/tmp/ut-run/zoneId", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zone/templates/test.conf b/tests/unit_tests/server/configs/ut-zone/templates/test.conf index 168aa21..a58f932 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/test.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/test.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [], diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in index 7778208..7df03e4 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in @@ -10,6 +10,7 @@ "enableDbusIntegration" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "/tmp/ut-run/~NAME~", "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf index 6e49c5b..5d5509b 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf @@ -10,6 +10,7 @@ "enableDbusIntegration" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], -- 2.7.4 From 3479483f4debddc67aca0c3edec2a8d06ed03911 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 7 Apr 2015 10:54:00 +0200 Subject: [PATCH 06/16] Optimize launchAsRoot when UID is 0 [Feature] Optimization in launchAsRoot function [Cause] There is no need to fork when we are already launched as root [Solution] Call func directly when UID is 0 [Verification] Build, install, run tests Change-Id: I25453b18329d1c5f353e4303d82836943d19528b --- common/utils/environment.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp index fc45321..511fcda 100644 --- a/common/utils/environment.cpp +++ b/common/utils/environment.cpp @@ -177,18 +177,22 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps) bool launchAsRoot(const std::function& func) { - // TODO optimize if getuid() == 0 - return executeAndWait([&func]() { - if (::setuid(0) < 0) { - LOGW("Failed to become root: " << getSystemErrorMessage()); - _exit(EXIT_FAILURE); - } - - if (!func()) { - LOGE("Failed to successfully execute func"); - _exit(EXIT_FAILURE); - } - }); + if (::getuid() == 0) { + // we are already root, no need to fork + return func(); + } else { + return executeAndWait([&func]() { + if (::setuid(0) < 0) { + LOGW("Failed to become root: " << getSystemErrorMessage()); + _exit(EXIT_FAILURE); + } + + if (!func()) { + LOGE("Failed to successfully execute func"); + _exit(EXIT_FAILURE); + } + }); + } } bool joinToNs(int nsPid, int ns) -- 2.7.4 From d230629cdf0a8c0df1747b7d0bc4f1ffeee01623 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Wed, 8 Apr 2015 13:36:17 +0200 Subject: [PATCH 07/16] Update tizen common (with wayland) lxc template [Bug/Feature] Adjust template to new platform image [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: If2771b8f39ca1422885fb241a7d7f0958b965065 Signed-off-by: Dariusz Michaluk --- server/configs/lxc-templates/tizen-common-wayland.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/server/configs/lxc-templates/tizen-common-wayland.sh b/server/configs/lxc-templates/tizen-common-wayland.sh index 5c572b7..48a2ff9 100755 --- a/server/configs/lxc-templates/tizen-common-wayland.sh +++ b/server/configs/lxc-templates/tizen-common-wayland.sh @@ -152,6 +152,20 @@ WantedBy=graphical.target EOF chmod 644 ${path}/systemd/system/display-manager-run.service +# TODO temporary solution to set proper access rights +cat <>${path}/systemd/system/ptmx-fix.service +[Unit] +Description=Temporary fix access rights + +[Service] +ExecStart=/bin/sh -c '/bin/chmod 666 /dev/ptmx; /bin/chown root:tty /dev/ptmx; /bin/chsmack -a "*" /dev/ptmx' + +[Install] +WantedBy=multi-user.target +EOF +chmod 644 ${path}/systemd/system/ptmx-fix.service +/bin/ln -s ${path}/systemd/system/ptmx-fix.service ${path}/systemd/system/multi-user.target.wants/ptmx-fix.service + sed -e 's/run\/display/tmp/g' /usr/lib/systemd/system/display-manager.path >> ${path}/systemd/system/display-manager.path chmod 644 ${path}/systemd/system/display-manager.path sed -e 's/run\/display/tmp/g' /usr/lib/systemd/system/display-manager.service >> ${path}/systemd/system/display-manager.service -- 2.7.4 From f3e8d507082928520ee9d876ec466cf159ee38fe Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 7 Apr 2015 15:41:58 +0200 Subject: [PATCH 08/16] Client refactor (using libConfig, switch to IPC #1) [Feature] Using libConfig for serialize parameters [Cause] Switching from Dbus to IPC [Solution] Using libConfig for serialize parameters [Verification] run tests with Valgrind Change-Id: I0562037cfc5b78b53024d0021ab74a0a1d3a3f3d --- client/CMakeLists.txt | 2 +- client/dbus-connection.cpp | 119 +++++ client/dbus-connection.hpp | 135 +++++ client/exception.hpp | 65 +++ client/host-dbus-connection.cpp | 191 +++++++ client/host-dbus-connection.hpp | 84 +++ client/vasum-client-impl.cpp | 1067 +++++++++++++++------------------------ client/vasum-client-impl.hpp | 72 +-- client/zone-dbus-connection.cpp | 71 +++ client/zone-dbus-connection.hpp | 60 +++ common/api/messages.hpp | 17 + 11 files changed, 1171 insertions(+), 712 deletions(-) create mode 100644 client/dbus-connection.cpp create mode 100644 client/dbus-connection.hpp create mode 100644 client/exception.hpp create mode 100644 client/host-dbus-connection.cpp create mode 100644 client/host-dbus-connection.hpp create mode 100644 client/zone-dbus-connection.cpp create mode 100644 client/zone-dbus-connection.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 558f3a7..7198610 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -44,7 +44,7 @@ SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY VERSION ${_LIB_VERSION_}) ## Link libraries ############################################################## -PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger) +PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger libConfig) INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) diff --git a/client/dbus-connection.cpp b/client/dbus-connection.cpp new file mode 100644 index 0000000..7e364d7 --- /dev/null +++ b/client/dbus-connection.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief libSimpleDbus's wrapper + */ + +#include +#include "dbus-connection.hpp" +#include "exception.hpp" +#include +#include + +using namespace vasum::client; + + +DbusConnection::DbusConnection(const std::string& definition, + const std::string& busName, + const std::string& objectPath, + const std::string& interface) + : mDefinition(definition) + , mBusName(busName) + , mObjectPath(objectPath) + , mInterface(interface) +{ +} + +DbusConnection::~DbusConnection() +{ +} + +void DbusConnection::create(const std::shared_ptr& connection) +{ + mConnection = connection; +} + +void DbusConnection::callMethod(const std::string& method, + GVariant* args_in, + const std::string& args_spec_out, + GVariant** args_out) +{ + dbus::GVariantPtr ret = mConnection->callMethod(mBusName, + mObjectPath, + mInterface, + method, + args_in, + args_spec_out); + if (args_out != NULL) { + *args_out = ret.release(); + } +} + +DbusConnection::SubscriptionId DbusConnection::signalSubscribe(const std::string& signal, + const SignalCallback& signalCallback) +{ + auto onSignal = [this, signal, signalCallback](const std::string& /*senderBusName*/, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant * parameters) { + if (objectPath == mObjectPath && + interface == mInterface && + signalName == signal) { + + signalCallback(parameters); + } + }; + return mConnection->signalSubscribe(onSignal, mBusName); +} + +void DbusConnection::signalUnsubscribe(SubscriptionId id) +{ + mConnection->signalUnsubscribe(id); +} + +std::string DbusConnection::getArgsOutSpec(const std::string& methodName) +{ + //TODO: Information about output argumnets of all methods can be computed in constuctor + GError *error = NULL; + GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(mDefinition.c_str(), &error); + if (error) { + std::string msg = error->message; + g_error_free (error); + throw ClientException("Invalid xml: " + msg); + } + GDBusInterfaceInfo* interfaceInfo = g_dbus_node_info_lookup_interface(nodeInfo, mInterface.c_str()); + if (interfaceInfo == NULL) { + throw ClientException("Invalid xml: can't find interface: " + mInterface); + } + GDBusMethodInfo* methodInfo = g_dbus_interface_info_lookup_method(interfaceInfo, methodName.c_str()); + if (methodInfo == NULL) { + throw ClientException("Invalid xml: can't find method: " + methodName); + } + + std::string signature; + for (GDBusArgInfo** argInfo = methodInfo->out_args; *argInfo; ++argInfo) { + signature += (*argInfo)->signature; + } + g_dbus_node_info_unref(nodeInfo); + return "(" + signature + ")"; +} diff --git a/client/dbus-connection.hpp b/client/dbus-connection.hpp new file mode 100644 index 0000000..a760bb6 --- /dev/null +++ b/client/dbus-connection.hpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief libSimpleDbus's wrapper + */ + +#ifndef VASUM_CLIENT_DBUS_CONNECTION_HPP +#define VASUM_CLIENT_DBUS_CONNECTION_HPP + +#include +#include +#include +#include +#include +#include + +namespace vasum { +namespace client { + +/** + * libSimpleDbus client definition. + * + * DbusConnection uses libSimpleDbus API. + */ +class DbusConnection { +public: + typedef unsigned int SubscriptionId; + + DbusConnection(const std::string& definition, + const std::string& busName, + const std::string& objectPath, + const std::string& interface); + virtual ~DbusConnection(); + void create(const std::shared_ptr& connection); + + template + typename std::enable_if::value>::type + call(const std::string& method, const ArgIn& argIn, ArgOut& argOut); + + template + typename std::enable_if::value>::type + call(const std::string& method, const ArgIn& argIn, ArgOut& argOut); + + template + typename std::enable_if::value>::type + call(const std::string& method, ArgOut& argOut) { + vasum::api::Void argIn; + call(method, argIn, argOut); + } + + template + typename std::enable_if::value>::type + call(const std::string& method, ArgIn& argIn) { + vasum::api::Void argOut; + call(method, argIn, argOut); + } + + template + SubscriptionId signalSubscribe(const std::string& signal, + const std::function& signalCallback); + void signalUnsubscribe(SubscriptionId id); + +private: + typedef std::function SignalCallback; + + std::shared_ptr mConnection; + const std::string mDefinition; + const std::string mBusName; + const std::string mObjectPath; + const std::string mInterface; + + void callMethod(const std::string& method, + GVariant* args_in, + const std::string& args_spec_out, + GVariant** args_out); + SubscriptionId signalSubscribe(const std::string& signal, const SignalCallback& signalCallback); + + /** + * Get signature of method output parameters + */ + std::string getArgsOutSpec(const std::string& methodName); +}; + +template +typename std::enable_if::value>::type +DbusConnection::call(const std::string& method, const ArgIn& argIn, ArgOut& argOut) +{ + GVariant* gArgOut = NULL; + callMethod(method, config::saveToGVariant(argIn), getArgsOutSpec(method), &gArgOut); + config::loadFromGVariant(gArgOut, argOut); + g_variant_unref(gArgOut); +} + +template +typename std::enable_if::value>::type +DbusConnection::call(const std::string& method, const ArgIn& argIn, ArgOut& /* argOut */) +{ + callMethod(method, config::saveToGVariant(argIn), "", NULL); +} + +template +DbusConnection::SubscriptionId DbusConnection::signalSubscribe(const std::string& signal, + const std::function& signalCallback) +{ + SignalCallback callback = [signalCallback](GVariant* parameters) { + Arg param; + config::loadFromGVariant(parameters, param); + signalCallback(param); + }; + return signalSubscribe(signal, callback); +} + +} // namespace client +} // namespace vasum + +#endif /* VASUM_CLIENT_DBUS_CONNECTION_HPP */ diff --git a/client/exception.hpp b/client/exception.hpp new file mode 100644 index 0000000..d4be66b --- /dev/null +++ b/client/exception.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Exceptions for the client + */ + + +#ifndef CLIENT_EXCEPTION_HPP +#define CLIENT_EXCEPTION_HPP + +#include "base-exception.hpp" + + +namespace vasum { + + +/** + * Base class for exceptions in Vasum Client + */ +struct ClientException: public VasumException { + + ClientException(const std::string& error) : VasumException(error) {} +}; + +struct IOException: public ClientException { + + IOException(const std::string& error) : ClientException(error) {} +}; + +struct OperationFailedException: public ClientException { + + OperationFailedException(const std::string& error) : ClientException(error) {} +}; + +struct InvalidArgumentException: public ClientException { + + InvalidArgumentException(const std::string& error) : ClientException(error) {} +}; + +struct InvalidResponseException: public ClientException { + + InvalidResponseException(const std::string& error) : ClientException(error) {} +}; + +} + +#endif // CLIENT_EXCEPTION_HPP diff --git a/client/host-dbus-connection.cpp b/client/host-dbus-connection.cpp new file mode 100644 index 0000000..7e511fe --- /dev/null +++ b/client/host-dbus-connection.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Host client class + */ + + +#include +#include "host-dbus-connection.hpp" +#include +#include + +namespace vasum { +namespace client { + +HostDbusConnection::HostDbusConnection() + : mConnection(vasum::api::host::DEFINITION, + vasum::api::host::BUS_NAME, + vasum::api::host::OBJECT_PATH, + vasum::api::host::INTERFACE) +{ +} + +void HostDbusConnection::create(const std::shared_ptr& connection) +{ + mConnection.create(connection); +} + +void HostDbusConnection::callGetZoneIds(vasum::api::ZoneIds& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_ID_LIST, argOut); +} + +void HostDbusConnection::callGetActiveZoneId(vasum::api::ZoneId& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ACTIVE_ZONE_ID, argOut); +} + +void HostDbusConnection::callSetActiveZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SET_ACTIVE_ZONE, argIn); +} + +void HostDbusConnection::callGetZoneInfo(const vasum::api::ZoneId& argIn, vasum::api::ZoneInfoOut& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_INFO, argIn, argOut); +} + +void HostDbusConnection::callSetNetdevAttrs(const vasum::api::SetNetDevAttrsIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SET_NETDEV_ATTRS, argIn); +} + +void HostDbusConnection::callGetNetdevAttrs(const vasum::api::GetNetDevAttrsIn& argIn, vasum::api::GetNetDevAttrs& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_NETDEV_ATTRS, argIn, argOut); +} + +void HostDbusConnection::callGetNetdevList(const vasum::api::ZoneId& argIn, vasum::api::NetDevList& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_NETDEV_LIST, argIn, argOut); +} + +void HostDbusConnection::callCreateNetdevVeth(const vasum::api::CreateNetDevVethIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_VETH, argIn); +} + +void HostDbusConnection::callCreateNetdevMacvlan(const vasum::api::CreateNetDevMacvlanIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_MACVLAN, argIn); +} + +void HostDbusConnection::callCreateNetdevPhys(const vasum::api::CreateNetDevPhysIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_PHYS, argIn); +} + +void HostDbusConnection::callDestroyNetdev(const vasum::api::DestroyNetDevIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DESTROY_NETDEV, argIn); +} + +void HostDbusConnection::callDeleteNetdevIpAddress(const vasum::api::DeleteNetdevIpAddressIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, argIn); +} + +void HostDbusConnection::callDeclareFile(const vasum::api::DeclareFileIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_FILE, argIn, argOut); +} + +void HostDbusConnection::callDeclareMount(const vasum::api::DeclareMountIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_MOUNT, argIn, argOut); +} + +void HostDbusConnection::callDeclareLink(const vasum::api::DeclareLinkIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_LINK, argIn, argOut); +} + +void HostDbusConnection::callGetDeclarations(const vasum::api::ZoneId& argIn, vasum::api::Declarations& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_DECLARATIONS, argIn, argOut); +} + +void HostDbusConnection::callRemoveDeclaration(const vasum::api::RemoveDeclarationIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_REMOVE_DECLARATION, argIn); +} + +void HostDbusConnection::callCreateZone(const vasum::api::CreateZoneIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_ZONE, argIn); +} + +void HostDbusConnection::callDestroyZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DESTROY_ZONE, argIn); +} + +void HostDbusConnection::callShutdownZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SHUTDOWN_ZONE, argIn); +} + +void HostDbusConnection::callStartZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_START_ZONE, argIn); +} + +void HostDbusConnection::callLockZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_LOCK_ZONE, argIn); +} + +void HostDbusConnection::callUnlockZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_UNLOCK_ZONE, argIn); +} + +void HostDbusConnection::callGrantDevice(const vasum::api::GrantDeviceIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_GRANT_DEVICE, argIn); +} + +void HostDbusConnection::callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_REVOKE_DEVICE, argIn); +} + +void HostDbusConnection::callGetZoneDbuses(vasum::api::Dbuses& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_DBUSES, argOut); +} + +HostDbusConnection::SubscriptionId +HostDbusConnection::subscribeZoneDbusState(const ZoneDbusStateCallback& callback) +{ + return mConnection.signalSubscribe( + vasum::api::host::SIGNAL_ZONE_DBUS_STATE, callback); +} + +void HostDbusConnection::unsubscribe(const SubscriptionId& id) +{ + mConnection.signalUnsubscribe(id); +} + +} // namespace client +} // namespace vasum diff --git a/client/host-dbus-connection.hpp b/client/host-dbus-connection.hpp new file mode 100644 index 0000000..c7cebdb --- /dev/null +++ b/client/host-dbus-connection.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Host client class + */ + +#ifndef VASUM_CLIENT_HOST_DBUS_CONNECTION_HPP +#define VASUM_CLIENT_HOST_DBUS_CONNECTION_HPP + +#include "dbus-connection.hpp" +#include + +namespace vasum { +namespace client { + +/** + * vasum's client definition. + * + * HostDbusConnection is used for communication with the vasum's server from host through dbus + */ +class HostDbusConnection { +public: + typedef unsigned int SubscriptionId; + typedef std::function ZoneDbusStateCallback; + + HostDbusConnection(); + + void create(const std::shared_ptr& connection); + + void callGetZoneIds(vasum::api::ZoneIds& argOut); + void callGetActiveZoneId(vasum::api::ZoneId& argOut); + void callSetActiveZone(const vasum::api::ZoneId& argIn); + void callGetZoneInfo(const vasum::api::ZoneId& argIn, vasum::api::ZoneInfoOut& argOut); + void callSetNetdevAttrs(const vasum::api::SetNetDevAttrsIn& argIn); + void callGetNetdevAttrs(const vasum::api::GetNetDevAttrsIn& argIn, vasum::api::GetNetDevAttrs& argOut); + void callGetNetdevList(const vasum::api::ZoneId& argIn, vasum::api::NetDevList& argOut); + void callCreateNetdevVeth(const vasum::api::CreateNetDevVethIn& argIn); + void callCreateNetdevMacvlan(const vasum::api::CreateNetDevMacvlanIn& argIn); + void callCreateNetdevPhys(const vasum::api::CreateNetDevPhysIn& argIn); + void callDestroyNetdev(const vasum::api::DestroyNetDevIn& argIn); + void callDeleteNetdevIpAddress(const vasum::api::DeleteNetdevIpAddressIn& argIn); + void callDeclareFile(const vasum::api::DeclareFileIn& argIn, vasum::api::Declaration& argOut); + void callDeclareMount(const vasum::api::DeclareMountIn& argIn, vasum::api::Declaration& argOut); + void callDeclareLink(const vasum::api::DeclareLinkIn& argIn, vasum::api::Declaration& argOut); + void callGetDeclarations(const vasum::api::ZoneId& argIn, vasum::api::Declarations& argOut); + void callRemoveDeclaration(const vasum::api::RemoveDeclarationIn& argIn); + void callCreateZone(const vasum::api::CreateZoneIn& argIn); + void callDestroyZone(const vasum::api::ZoneId& argIn); + void callShutdownZone(const vasum::api::ZoneId& argIn); + void callStartZone(const vasum::api::ZoneId& argIn); + void callLockZone(const vasum::api::ZoneId& argIn); + void callUnlockZone(const vasum::api::ZoneId& argIn); + void callGrantDevice(const vasum::api::GrantDeviceIn& argIn); + void callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn); + void callGetZoneDbuses(vasum::api::Dbuses& argOut); + SubscriptionId subscribeZoneDbusState(const ZoneDbusStateCallback& callback); + void unsubscribe(const SubscriptionId& id); +private: + DbusConnection mConnection; +}; + +} // namespace client +} // namespace vasum + +#endif /* VASUM_CLIENT_HOST_DBUS_CONNECTION_HPP */ diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 4f3a05c..41a0030 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -26,15 +26,16 @@ #include #include "vasum-client-impl.hpp" #include "utils.hpp" +#include "exception.hpp" +#include "host-dbus-connection.hpp" +#include "zone-dbus-connection.hpp" +#include + #include #include #include -#include -#include -#include #include -#include #include #include #include @@ -46,71 +47,11 @@ #include using namespace std; -using namespace dbus; using namespace vasum; -using namespace vasum::utils; namespace { -const DbusInterfaceInfo HOST_INTERFACE(api::host::BUS_NAME, - api::host::OBJECT_PATH, - api::host::INTERFACE); -const DbusInterfaceInfo ZONE_INTERFACE(api::zone::BUS_NAME, - api::zone::OBJECT_PATH, - api::zone::INTERFACE); - -unique_ptr gGlibLoop; - -void toDict(GVariant* in, VsmArrayString* keys, VsmArrayString* values) -{ - assert(in); - assert(keys); - assert(values); - - typedef char* key_type; - typedef char* value_type; - - GVariantIter iter; - value_type value; - key_type key; - gsize size = g_variant_n_children(in); - key_type* outk = (key_type*)calloc(size + 1, sizeof(key_type)); - value_type* outv = (value_type*)calloc(size + 1, sizeof(value_type)); - - g_variant_iter_init(&iter, in); - for (int i = 0; g_variant_iter_loop(&iter, "(ss)", &key, &value); i++) { - outk[i] = strdup(key); - outv[i] = strdup(value); - } - *keys = outk; - *values = outv; -} - -vector> toDict(GVariant* in) -{ - assert(in); - - const gchar* key; - const gchar* value; - vector> dict; - GVariantIter iter; - g_variant_iter_init(&iter, in); - while (g_variant_iter_loop(&iter, "(&s&s)", &key, &value)) { - dict.push_back(make_tuple(key, value)); - } - return dict; -} - -void toBasic(GVariant* in, char** str) -{ - assert(in); - assert(str); - - gsize length; - const gchar* src = g_variant_get_string(in, &length); - char* buf = strndup(src, length); - *str = buf; -} +unique_ptr gGlibLoop; VsmZoneState getZoneState(const char* state) { @@ -137,43 +78,35 @@ VsmZoneState getZoneState(const char* state) } else if (strcmp(state, "ACTIVATING") == 0) { return ACTIVATING; } - assert(0 && "UNKNOWN STATE"); - return (VsmZoneState)-1; + throw InvalidResponseException("Unknown state"); } -void toBasic(GVariant* in, VsmZone* zone) +void convert(const api::VectorOfStrings& in, VsmArrayString& out) { - const char* id; - const char* path; - const char* state; - int terminal; - VsmZone vsmZone = (VsmZone)malloc(sizeof(*vsmZone)); - g_variant_get(in, "(siss)", &id, &terminal, &state, &path); - vsmZone->id = strdup(id); - vsmZone->terminal = terminal; - vsmZone->state = getZoneState(state); - vsmZone->rootfs_path = strdup(path); - *zone = vsmZone; + out = reinterpret_cast(calloc(in.values.size() + 1, sizeof(char*))); + for (size_t i = 0; i < in.values.size(); ++i) { + out[i] = ::strdup(in.values[i].c_str()); + } } -template -void toArray(GVariant* in, T** scArray) +void convert(const api::VectorOfStringPairs& in, VsmArrayString& keys, VsmArrayString& values) { - assert(in); - assert(scArray); - - gsize size = g_variant_n_children(in); - T* ids = (T*)calloc(size + 1, sizeof(T)); - - GVariantIter iter; - GVariant* child; - - g_variant_iter_init(&iter, in); - for (int i = 0; (child = g_variant_iter_next_value(&iter)); i++) { - toBasic(child, &ids[i]); - g_variant_unref(child); + keys = reinterpret_cast(calloc(in.values.size() + 1, sizeof(char*))); + values = reinterpret_cast(calloc(in.values.size() + 1, sizeof(char*))); + for (size_t i = 0; i < in.values.size(); ++i) { + keys[i] = ::strdup(in.values[i].first.c_str()); + values[i] = ::strdup(in.values[i].second.c_str()); } - *scArray = ids; +} + +void convert(const api::ZoneInfoOut& info, VsmZone& zone) +{ + VsmZone vsmZone = reinterpret_cast(malloc(sizeof(*vsmZone))); + vsmZone->id = ::strdup(info.id.c_str()); + vsmZone->terminal = info.vt; + vsmZone->state = getZoneState(info.state.c_str()); + vsmZone->rootfs_path = ::strdup(info.rootPath.c_str()); + zone = vsmZone; } string toString(const in_addr* addr) @@ -181,7 +114,7 @@ string toString(const in_addr* addr) char buf[INET_ADDRSTRLEN]; const char* ret = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); if (ret == NULL) { - throw runtime_error(getSystemErrorMessage()); + throw InvalidArgumentException(getSystemErrorMessage()); } return ret; } @@ -191,37 +124,11 @@ string toString(const in6_addr* addr) char buf[INET6_ADDRSTRLEN]; const char* ret = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN); if (ret == NULL) { - throw runtime_error(getSystemErrorMessage()); + throw InvalidArgumentException(getSystemErrorMessage()); } return ret; } -GVariant* createTupleArray(const vector>& dict) -{ - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); - for (const auto entry : dict) { - g_variant_builder_add(&builder, "(ss)", get<0>(entry).c_str(), get<1>(entry).c_str()); - } - return g_variant_builder_end(&builder); -} - -VsmStatus toStatus(const exception& ex) -{ - if (typeid(DbusCustomException) == typeid(ex)) { - return VSMCLIENT_CUSTOM_ERROR; - } else if (typeid(DbusIOException) == typeid(ex)) { - return VSMCLIENT_IO_ERROR; - } else if (typeid(DbusOperationException) == typeid(ex)) { - return VSMCLIENT_OPERATION_FAILED; - } else if (typeid(DbusInvalidArgumentException) == typeid(ex)) { - return VSMCLIENT_INVALID_ARGUMENT; - } else if (typeid(DbusException) == typeid(ex)) { - return VSMCLIENT_OTHER_ERROR; - } - return VSMCLIENT_OTHER_ERROR; -} - bool readFirstLineOfFile(const string& path, string& ret) { ifstream file(path); @@ -235,39 +142,15 @@ bool readFirstLineOfFile(const string& path, string& ret) } //namespace -VsmStatus Client::getNetdevAttrs(const string& zone, - const string& netdev, - NetdevAttrs& attrs) noexcept -{ - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(ss)", zone.c_str(), netdev.c_str()); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_NETDEV_ATTRS, - args_in, - "(a(ss))", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - attrs = toDict(unpacked); - g_variant_unref(unpacked); - g_variant_unref(out); - mStatus = Status(); - return vsm_get_status(); -} - VsmStatus Client::vsm_start_glib_loop() noexcept { try { if (!gGlibLoop) { - gGlibLoop.reset(new ScopedGlibLoop()); + gGlibLoop.reset(new utils::ScopedGlibLoop()); } } catch (const exception&) { return VSMCLIENT_OTHER_ERROR; } - return VSMCLIENT_SUCCESS; } @@ -299,89 +182,55 @@ Client::~Client() noexcept { } -VsmStatus Client::createSystem() noexcept +VsmStatus Client::coverException(const function worker) noexcept { try { - mConnection = DbusConnection::createSystem(); - mStatus = Status(); + worker(); + mStatus = Status(VSMCLIENT_SUCCESS); + } catch (const vasum::IOException& ex) { + mStatus = Status(VSMCLIENT_IO_ERROR, ex.what()); + } catch (const vasum::OperationFailedException& ex) { + mStatus = Status(VSMCLIENT_OPERATION_FAILED, ex.what()); + } catch (const vasum::InvalidArgumentException& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + } catch (const vasum::InvalidResponseException& ex) { + mStatus = Status(VSMCLIENT_OTHER_ERROR, ex.what()); + } catch (const vasum::ClientException& ex) { + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what()); + } catch (const dbus::DbusCustomException& ex) { + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what()); + } catch (const dbus::DbusIOException& ex) { + mStatus = Status(VSMCLIENT_IO_ERROR, ex.what()); + } catch (const dbus::DbusOperationException& ex) { + mStatus = Status(VSMCLIENT_OPERATION_FAILED, ex.what()); + } catch (const dbus::DbusInvalidArgumentException& ex) { + mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); + } catch (const dbus::DbusException& ex) { + mStatus = Status(VSMCLIENT_OTHER_ERROR, ex.what()); } catch (const exception& ex) { - mStatus = Status(toStatus(ex), ex.what()); + mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what()); } - return vsm_get_status(); + return mStatus.mVsmStatus; } -VsmStatus Client::create(const string& address) noexcept +VsmStatus Client::createSystem() noexcept { - try { - mConnection = DbusConnection::create(address); - mStatus = Status(); - } catch (const exception& ex) { - mStatus = Status(toStatus(ex), ex.what()); - } - return vsm_get_status(); -} + return coverException([&] { + shared_ptr connection(dbus::DbusConnection::createSystem().release()); -VsmStatus Client::callMethod(const DbusInterfaceInfo& info, - const string& method, - GVariant* args_in, - const string& args_spec_out, - GVariant** args_out) -{ - try { - GVariantPtr ret = mConnection->callMethod(info.busName, - info.objectPath, - info.interface, - method, - args_in, - args_spec_out); - if (args_out != NULL) { - *args_out = ret.release(); - } - mStatus = Status(); - } catch (const exception& ex) { - mStatus = Status(toStatus(ex), ex.what()); - } - return vsm_get_status(); + mHostClient.create(connection); + mZoneClient.create(connection); + }); } -VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info, - const string& name, - SignalCallback signalCallback, - VsmSubscriptionId* subscriptionId) +VsmStatus Client::create(const string& address) noexcept { - auto onSignal = [=](const string& /*senderBusName*/, - const string & objectPath, - const string & interface, - const string & signalName, - GVariant * parameters) { - if (objectPath == info.objectPath && - interface == info.interface && - signalName == name) { - - signalCallback(parameters); - } - }; - try { - guint id = mConnection->signalSubscribe(onSignal, info.busName); - if (subscriptionId) { - *subscriptionId = id; - } - mStatus = Status(); - } catch (const exception& ex) { - mStatus = Status(toStatus(ex), ex.what()); - } - return vsm_get_status(); -} + return coverException([&] { + shared_ptr connection(dbus::DbusConnection::create(address).release()); -VsmStatus Client::signalUnsubscribe(VsmSubscriptionId id) -{ - try { - mConnection->signalUnsubscribe(id); - mStatus = Status(); - } catch (const exception& ex) { - mStatus = Status(toStatus(ex), ex.what()); - } - return vsm_get_status(); + mHostClient.create(connection); + mZoneClient.create(connection); + }); } const char* Client::vsm_get_status_message() const noexcept @@ -399,86 +248,54 @@ VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* keys, VsmArrayString* valu assert(keys); assert(values); - GVariant* out = NULL; - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_ZONE_DBUSES, - NULL, - "(a(ss))", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toDict(unpacked, keys, values); - g_variant_unref(unpacked); - g_variant_unref(out); - return ret; + return coverException([&] { + api::Dbuses dbuses; + mHostClient.callGetZoneDbuses(dbuses); + convert(dbuses, *keys, *values); + }); } VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept { assert(array); - GVariant* out = NULL; - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_ZONE_ID_LIST, - NULL, - "(as)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toArray(unpacked, array); - g_variant_unref(unpacked); - g_variant_unref(out); - return ret; + return coverException([&] { + api::ZoneIds zoneIds; + mHostClient.callGetZoneIds(zoneIds); + convert(zoneIds, *array); + }); } VsmStatus Client::vsm_get_active_zone_id(VsmString* id) noexcept { assert(id); - GVariant* out = NULL; - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_ACTIVE_ZONE_ID, - NULL, - "(s)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toBasic(unpacked, id); - g_variant_unref(unpacked); - g_variant_unref(out); - return ret; + return coverException([&] { + api::ZoneId zoneId; + mHostClient.callGetActiveZoneId(zoneId); + *id = ::strdup(zoneId.value.c_str()); + }); } VsmStatus Client::vsm_lookup_zone_by_pid(int pid, VsmString* id) noexcept { assert(id); - const string path = "/proc/" + to_string(pid) + "/cpuset"; + return coverException([&] { + const string path = "/proc/" + to_string(pid) + "/cpuset"; - string cpuset; - if (!readFirstLineOfFile(path, cpuset)) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, "Process not found"); - return vsm_get_status(); - } + string cpuset; + if (!readFirstLineOfFile(path, cpuset)) { + throw InvalidArgumentException("Process not found"); + } - string zoneId; - if (!parseZoneIdFromCpuSet(cpuset, zoneId)) { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "unknown format of cpuset"); - return vsm_get_status(); - } + string zoneId; + if (!parseZoneIdFromCpuSet(cpuset, zoneId)) { + throw OperationFailedException("unknown format of cpuset"); + } - *id = strdup(zoneId.c_str()); - mStatus = Status(); - return vsm_get_status(); + *id = ::strdup(zoneId.c_str()); + }); } VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept @@ -486,104 +303,111 @@ VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept assert(id); assert(zone); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(s)", id); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_ZONE_INFO, - args_in, - "(siss)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - toBasic(out, zone); - g_variant_unref(out); - return ret; + return coverException([&] { + api::ZoneInfoOut info; + mHostClient.callGetZoneInfo({ id }, info); + convert(info, *zone); + }); } VsmStatus Client::vsm_lookup_zone_by_terminal_id(int, VsmString*) noexcept { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented"); - return vsm_get_status(); + return coverException([&] { + throw OperationFailedException("Not implemented"); + }); } VsmStatus Client::vsm_set_active_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_SET_ACTIVE_ZONE, args_in); + return coverException([&] { + mHostClient.callSetActiveZone({ id }); + }); } VsmStatus Client::vsm_create_zone(const char* id, const char* tname) noexcept { assert(id); - const char* template_name = tname ? tname : "default"; - GVariant* args_in = g_variant_new("(ss)", id, template_name); - return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_ZONE, args_in); + return coverException([&] { + string template_name = tname ? tname : "default"; + mHostClient.callCreateZone({ id, template_name }); + }); } VsmStatus Client::vsm_destroy_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_DESTROY_ZONE, args_in); + + return coverException([&] { + mHostClient.callDestroyZone({ id }); + }); } VsmStatus Client::vsm_shutdown_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_SHUTDOWN_ZONE, args_in); + + return coverException([&] { + mHostClient.callShutdownZone({ id }); + }); } VsmStatus Client::vsm_start_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_START_ZONE, args_in); + + return coverException([&] { + mHostClient.callStartZone({ id }); + }); } VsmStatus Client::vsm_lock_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_LOCK_ZONE, args_in); + return coverException([&] { + mHostClient.callLockZone({ id }); + }); } VsmStatus Client::vsm_unlock_zone(const char* id) noexcept { assert(id); - GVariant* args_in = g_variant_new("(s)", id); - return callMethod(HOST_INTERFACE, api::host::METHOD_UNLOCK_ZONE, args_in); + return coverException([&] { + mHostClient.callUnlockZone({ id }); + }); } VsmStatus Client::vsm_add_state_callback(VsmZoneDbusStateCallback zoneDbusStateCallback, - void* data, - VsmSubscriptionId* subscriptionId) noexcept + void* data, + VsmSubscriptionId* subscriptionId) noexcept { assert(zoneDbusStateCallback); - auto onSigal = [=](GVariant * parameters) - { - const char* zone; - const char* dbusAddress; - g_variant_get(parameters, "(&s&s)", &zone, &dbusAddress); - zoneDbusStateCallback(zone, dbusAddress, data); - }; - - return signalSubscribe(HOST_INTERFACE, - api::host::SIGNAL_ZONE_DBUS_STATE, - onSigal, - subscriptionId); + return coverException([&] { + auto onSigal = [=](const api::DbusState& dbus) + { + zoneDbusStateCallback(dbus.first.c_str(), + dbus.second.c_str(), + data); + }; + + VsmSubscriptionId id; + id = mHostClient.subscribeZoneDbusState(onSigal); + if (subscriptionId) { + *subscriptionId = id; + } + }); } VsmStatus Client::vsm_del_state_callback(VsmSubscriptionId subscriptionId) noexcept { - return signalUnsubscribe(subscriptionId); + return coverException([&] { + mHostClient.unsubscribe(subscriptionId); + }); } VsmStatus Client::vsm_grant_device(const char* id, const char* device, uint32_t flags) noexcept @@ -591,8 +415,9 @@ VsmStatus Client::vsm_grant_device(const char* id, const char* device, uint32_t assert(id); assert(device); - GVariant* args_in = g_variant_new("(ssu)", id, device, flags); - return callMethod(HOST_INTERFACE, api::host::METHOD_GRANT_DEVICE, args_in); + return coverException([&] { + mHostClient.callGrantDevice({ id, device, flags }); + }); } VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept @@ -600,403 +425,328 @@ VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept assert(id); assert(device); - GVariant* args_in = g_variant_new("(ss)", id, device); - return callMethod(HOST_INTERFACE, api::host::METHOD_REVOKE_DEVICE, args_in); + return coverException([&] { + mHostClient.callRevokeDevice({ id, device }); + }); } -VsmStatus Client::vsm_zone_get_netdevs(const char* zone, VsmArrayString* netdevIds) noexcept +VsmStatus Client::vsm_zone_get_netdevs(const char* id, VsmArrayString* netdevIds) noexcept { - assert(zone); + assert(id); assert(netdevIds); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(s)", zone); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_NETDEV_LIST, - args_in, - "(as)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toArray(unpacked, netdevIds); - g_variant_unref(unpacked); - g_variant_unref(out); - return ret; + return coverException([&] { + api::NetDevList netdevs; + mHostClient.callGetNetdevList({ id }, netdevs); + convert(netdevs, *netdevIds); + }); } -VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* zone, - const char* netdevId, - struct in_addr* addr) noexcept +VsmStatus Client::vsm_netdev_get_ip_addr(const char* id, + const char* netdevId, + int type, + void* addr) noexcept { using namespace boost::algorithm; - assert(zone); + assert(id); assert(netdevId); assert(addr); - NetdevAttrs attrs; - VsmStatus ret = getNetdevAttrs(zone, netdevId, attrs); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - - auto it = find_if(attrs.begin(), attrs.end(), [](const tuple& entry) { - return get<0>(entry) == "ipv4"; - }); - if (it != attrs.end()) { - vector addrAttrs; - for(auto addrAttr : split(addrAttrs, get<1>(*it), is_any_of(","))) { - size_t pos = addrAttr.find(":"); - if (addrAttr.substr(0, pos) == "ip") { - if (pos != string::npos && pos < addrAttr.length() && - inet_pton(AF_INET, addrAttr.substr(pos + 1).c_str(), addr) == 1) { - //XXX: return only one address - mStatus = Status(); - return vsm_get_status(); - } else { - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Invalid response data"); - return vsm_get_status(); + return coverException([&] { + api::GetNetDevAttrs attrs; + mHostClient.callGetNetdevAttrs({ id, netdevId }, attrs); + + auto it = find_if(attrs.values.begin(), + attrs.values.end(), + [type](const api::StringPair& entry) { + return entry.first == (type == AF_INET ? "ipv4" : "ipv6"); + }); + + if (it != attrs.values.end()) { + vector addrAttrs; + for(auto addrAttr : split(addrAttrs, it->second, is_any_of(","))) { + size_t pos = addrAttr.find(":"); + if (addrAttr.substr(0, pos) == "ip") { + if (pos != string::npos && pos < addrAttr.length() && + inet_pton(type, addrAttr.substr(pos + 1).c_str(), addr) == 1) { + //XXX: return only one address + return; + } else { + throw InvalidResponseException("Wrong address format returned"); + } } } } - } - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Address not found"); - return vsm_get_status(); + throw OperationFailedException("Address not found"); + }); } -VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* zone, - const char* netdevId, - struct in6_addr* addr) noexcept +VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* id, + const char* netdevId, + struct in_addr* addr) noexcept { - using namespace boost::algorithm; + return vsm_netdev_get_ip_addr(id, netdevId, AF_INET, addr); +} - assert(zone); +VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* id, + const char* netdevId, + struct in6_addr* addr) noexcept +{ + return vsm_netdev_get_ip_addr(id, netdevId, AF_INET6, addr); +} + +VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* id, + const char* netdevId, + struct in_addr* addr, + int prefix) noexcept +{ + assert(id); assert(netdevId); assert(addr); - NetdevAttrs attrs; - VsmStatus ret = getNetdevAttrs(zone, netdevId, attrs); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - - auto it = find_if(attrs.begin(), attrs.end(), [](const tuple& entry) { - return get<0>(entry) == "ipv6"; + return coverException([&] { + string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix); + mHostClient.callSetNetdevAttrs({ id, netdevId, { { "ipv4", value } } } ); }); - if (it != attrs.end()) { - vector addrAttrs; - for(auto addrAttr : split(addrAttrs, get<1>(*it), is_any_of(","))) { - size_t pos = addrAttr.find(":"); - if (addrAttr.substr(0, pos) == "ip") { - if (pos != string::npos && pos < addrAttr.length() && - inet_pton(AF_INET6, addrAttr.substr(pos + 1).c_str(), addr) == 1) { - //XXX: return only one address - mStatus = Status(); - return vsm_get_status(); - } else { - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Invalid response data"); - return vsm_get_status(); - } - } - } - } - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Address not found"); - return vsm_get_status(); } -VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* zone, - const char* netdevId, - struct in_addr* addr, - int prefix) noexcept +VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* id, + const char* netdevId, + struct in6_addr* addr, + int prefix) noexcept { - try { - GVariant* dict = createTupleArray({make_tuple("ipv4", - "ip:" + toString(addr) + "," - "prefixlen:" + to_string(prefix))}); - GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); - return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); - } catch (exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } -} + assert(id); + assert(netdevId); + assert(addr); -VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* zone, - const char* netdevId, - struct in6_addr* addr, - int prefix) noexcept -{ - try { - GVariant* dict = createTupleArray({make_tuple("ipv6", - "ip:" + toString(addr) + "," - "prefixlen:" + to_string(prefix))}); - GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); - return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); - } catch (exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } + return coverException([&] { + string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix); + mHostClient.callSetNetdevAttrs({ id, netdevId, { { "ipv6", value } } } ); + }); } -VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* zone, - const char* netdevId, - struct in_addr* addr, - int prefix) noexcept +VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* id, + const char* netdevId, + struct in_addr* addr, + int prefix) noexcept { - std::string ip; - try { - //CIDR notation - ip = toString(addr) + "/" + to_string(prefix); - } catch(const std::exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } + assert(id); + assert(netdevId); + assert(addr); - GVariant* args_in = g_variant_new("(sss)", zone, netdevId, ip.c_str()); - return callMethod(HOST_INTERFACE, api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, args_in); + return coverException([&] { + //CIDR notation + string ip = toString(addr) + "/" + to_string(prefix); + mHostClient.callDeleteNetdevIpAddress({ id, netdevId, ip }); + }); } -VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* zone, - const char* netdevId, - struct in6_addr* addr, - int prefix) noexcept +VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* id, + const char* netdevId, + struct in6_addr* addr, + int prefix) noexcept { + assert(id); + assert(netdevId); + assert(addr); - std::string ip; - try { + return coverException([&] { //CIDR notation - ip = toString(addr) + "/" + to_string(prefix); - } catch(const std::exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } - - GVariant* args_in = g_variant_new("(sss)", zone, netdevId, ip.c_str()); - return callMethod(HOST_INTERFACE, api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, args_in); + string ip = toString(addr) + "/" + to_string(prefix); + mHostClient.callDeleteNetdevIpAddress({ id, netdevId, ip }); + }); } -VsmStatus Client::vsm_netdev_up(const char* zone, const char* netdevId) noexcept +VsmStatus Client::vsm_netdev_up(const char* id, const char* netdevId) noexcept { - try { - GVariant* dict = createTupleArray({make_tuple("flags", to_string(IFF_UP)), - make_tuple("change", to_string(IFF_UP))}); - GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); - return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); - } catch (exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } + assert(id); + assert(netdevId); + + return coverException([&] { + mHostClient.callSetNetdevAttrs({ id, netdevId, { { "flags", to_string(IFF_UP) }, + { "change", to_string(IFF_UP) } } } ); + }); } -VsmStatus Client::vsm_netdev_down(const char* zone, const char* netdevId) noexcept +VsmStatus Client::vsm_netdev_down(const char* id, const char* netdevId) noexcept { - try { - GVariant* dict = createTupleArray({make_tuple("flags", to_string(~IFF_UP)), - make_tuple("change", to_string(IFF_UP))}); - GVariant* args_in = g_variant_new("(ss@a(ss))", zone, netdevId, dict); - return callMethod(HOST_INTERFACE, api::host::METHOD_SET_NETDEV_ATTRS, args_in); - } catch (exception& ex) { - mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what()); - return vsm_get_status(); - } + assert(id); + assert(netdevId); + + return coverException([&] { + mHostClient.callSetNetdevAttrs({ id, netdevId, { { "flags", to_string(~IFF_UP) }, + { "change", to_string(IFF_UP) } } } ); + }); } -VsmStatus Client::vsm_create_netdev_veth(const char* zone, - const char* zoneDev, - const char* hostDev) noexcept +VsmStatus Client::vsm_create_netdev_veth(const char* id, + const char* zoneDev, + const char* hostDev) noexcept { - GVariant* args_in = g_variant_new("(sss)", zone, zoneDev, hostDev); - return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_VETH, args_in); + assert(id); + assert(zoneDev); + assert(hostDev); + + return coverException([&] { + mHostClient.callCreateNetdevVeth({ id, zoneDev, hostDev }); + }); } -VsmStatus Client::vsm_create_netdev_macvlan(const char* zone, - const char* zoneDev, - const char* hostDev, - enum macvlan_mode mode) noexcept +VsmStatus Client::vsm_create_netdev_macvlan(const char* id, + const char* zoneDev, + const char* hostDev, + enum macvlan_mode mode) noexcept { - GVariant* args_in = g_variant_new("(sssu)", zone, zoneDev, hostDev, mode); - return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_MACVLAN, args_in); + assert(id); + assert(zoneDev); + assert(hostDev); + + return coverException([&] { + mHostClient.callCreateNetdevMacvlan({ id, zoneDev, hostDev, mode }); + }); } -VsmStatus Client::vsm_create_netdev_phys(const char* zone, const char* devId) noexcept +VsmStatus Client::vsm_create_netdev_phys(const char* id, const char* devId) noexcept { - GVariant* args_in = g_variant_new("(ss)", zone, devId); - return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_NETDEV_PHYS, args_in); + assert(id); + assert(devId); + + return coverException([&] { + mHostClient.callCreateNetdevPhys({ id, devId }); + }); } -VsmStatus Client::vsm_lookup_netdev_by_name(const char* zone, - const char* netdevId, - VsmNetdev* netdev) noexcept +VsmStatus Client::vsm_lookup_netdev_by_name(const char* id, + const char* netdevId, + VsmNetdev* netdev) noexcept { using namespace boost::algorithm; - assert(zone); + assert(id); assert(netdevId); assert(netdev); - NetdevAttrs attrs; - VsmStatus ret = getNetdevAttrs(zone, netdevId, attrs); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - - auto it = find_if(attrs.begin(), attrs.end(), [](const tuple& entry) { - return get<0>(entry) == "type"; - }); - - VsmNetdevType type; - if (it == attrs.end()) { - mStatus = Status(VSMCLIENT_OTHER_ERROR, "Can't fetch netdev type"); - return vsm_get_status(); - } + return coverException([&] { + api::GetNetDevAttrs attrs; + mHostClient.callGetNetdevAttrs({ id, netdevId }, attrs); + auto it = find_if(attrs.values.begin(), + attrs.values.end(), + [](const api::StringPair& entry) { + return entry.first == "type"; + }); + + VsmNetdevType type; + if (it == attrs.values.end()) { + throw OperationFailedException("Can't fetch netdev type"); + } - switch (stoi(get<1>(*it))) { - case 1<<0 /*IFF_802_1Q_VLAN*/: type = VSMNETDEV_VETH; break; - case 1<<21 /*IFF_MACVLAN*/: type = VSMNETDEV_MACVLAN; break; - default: - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, "Unknown netdev type: " + get<1>(*it)); - return vsm_get_status(); - } + switch (stoi(it->second)) { + case 1<<0 /*IFF_802_1Q_VLAN*/: type = VSMNETDEV_VETH; break; + case 1<<21 /*IFF_MACVLAN*/: type = VSMNETDEV_MACVLAN; break; + default: + throw InvalidResponseException("Unknown netdev type: " + it->second); + } - *netdev = reinterpret_cast(malloc(sizeof(**netdev))); - (*netdev)->name = strdup(zone); - (*netdev)->type = type; - mStatus = Status(); - return vsm_get_status(); + *netdev = reinterpret_cast(malloc(sizeof(**netdev))); + (*netdev)->name = ::strdup(id); + (*netdev)->type = type; + }); } -VsmStatus Client::vsm_destroy_netdev(const char* zone, const char* devId) noexcept +VsmStatus Client::vsm_destroy_netdev(const char* id, const char* devId) noexcept { - GVariant* args_in = g_variant_new("(ss)", zone, devId); - return callMethod(HOST_INTERFACE, api::host::METHOD_DESTROY_NETDEV, args_in); + assert(id); + assert(devId); + + return coverException([&] { + mHostClient.callDestroyNetdev({ id, devId }); + }); } -VsmStatus Client::vsm_declare_file(const char* zone, - VsmFileType type, - const char *path, - int32_t flags, - mode_t mode, - VsmString* id) noexcept +VsmStatus Client::vsm_declare_file(const char* id, + VsmFileType type, + const char *path, + int32_t flags, + mode_t mode, + VsmString* declarationId) noexcept { + assert(id); assert(path); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(sisii)", zone, type, path, flags, mode); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_DECLARE_FILE, - args_in, - "(s)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - if (id != NULL) { - g_variant_get(out, "(*)", &unpacked); - toBasic(unpacked, id); - g_variant_unref(unpacked); - } - g_variant_unref(out); - return ret; + return coverException([&] { + api::Declaration declaration; + mHostClient.callDeclareFile({ id, type, path, flags, (int)mode }, declaration); + if (declarationId != NULL) { + *declarationId = ::strdup(declaration.value.c_str()); + } + }); } VsmStatus Client::vsm_declare_mount(const char *source, - const char* zone, - const char *target, - const char *type, - uint64_t flags, - const char *data, - VsmString* id) noexcept + const char* id, + const char *target, + const char *type, + uint64_t flags, + const char *data, + VsmString* declarationId) noexcept { assert(source); + assert(id); assert(target); assert(type); if (!data) { data = ""; } - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(ssssts)", source, zone, target, type, flags, data); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_DECLARE_MOUNT, - args_in, - "(s)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - if (id != NULL) { - g_variant_get(out, "(*)", &unpacked); - toBasic(unpacked, id); - g_variant_unref(unpacked); - } - g_variant_unref(out); - return ret; + return coverException([&] { + api::Declaration declaration; + mHostClient.callDeclareMount({ source, id, target, type, flags, data }, declaration); + if (declarationId != NULL) { + *declarationId = ::strdup(declaration.value.c_str()); + } + }); } -VsmStatus Client::vsm_declare_link(const char *source, - const char* zone, - const char *target, - VsmString* id) noexcept +VsmStatus Client::vsm_declare_link(const char* source, + const char* id, + const char* target, + VsmString* declarationId) noexcept { assert(source); + assert(id); assert(target); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(sss)", source, zone, target); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_DECLARE_LINK, - args_in, - "(s)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - if (id != NULL) { - g_variant_get(out, "(*)", &unpacked); - toBasic(unpacked, id); - g_variant_unref(unpacked); - } - g_variant_unref(out); - return ret; + return coverException([&] { + api::Declaration declaration; + mHostClient.callDeclareLink({ source, id, target }, declaration); + if (declarationId != NULL) { + *declarationId = ::strdup(declaration.value.c_str()); + } + }); } -VsmStatus Client::vsm_list_declarations(const char* zone, VsmArrayString* declarations) +VsmStatus Client::vsm_list_declarations(const char* id, VsmArrayString* declarations) noexcept { + assert(id); assert(declarations); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(s)", zone); - VsmStatus ret = callMethod(HOST_INTERFACE, - api::host::METHOD_GET_DECLARATIONS, - args_in, - "(as)", - &out); - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - GVariant* unpacked; - g_variant_get(out, "(*)", &unpacked); - toArray(unpacked, declarations); - g_variant_unref(unpacked); - g_variant_unref(out); - return ret; + return coverException([&] { + api::Declarations declarationsOut; + mHostClient.callGetDeclarations({ id }, declarationsOut); + convert(declarationsOut, *declarations); + }); } -VsmStatus Client::vsm_remove_declaration(const char* zone, VsmString declaration) +VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) noexcept { + assert(id); assert(declaration); - GVariant* args_in = g_variant_new("(ss)", zone, declaration); - return callMethod(HOST_INTERFACE, - api::host::METHOD_REMOVE_DECLARATION, - args_in); + return coverException([&] { + mHostClient.callRemoveDeclaration({ id, declaration }); + }); } VsmStatus Client::vsm_notify_active_zone(const char* application, const char* message) noexcept @@ -1004,10 +754,9 @@ VsmStatus Client::vsm_notify_active_zone(const char* application, const char* me assert(application); assert(message); - GVariant* args_in = g_variant_new("(ss)", application, message); - return callMethod(ZONE_INTERFACE, - api::zone::METHOD_NOTIFY_ACTIVE_ZONE, - args_in); + return coverException([&] { + mZoneClient.callNotifyActiveZone({ application, message }); + }); } VsmStatus Client::vsm_file_move_request(const char* destZone, const char* path) noexcept @@ -1015,50 +764,42 @@ VsmStatus Client::vsm_file_move_request(const char* destZone, const char* path) assert(destZone); assert(path); - GVariant* out = NULL; - GVariant* args_in = g_variant_new("(ss)", destZone, path); - VsmStatus ret = callMethod(ZONE_INTERFACE, - api::zone::METHOD_FILE_MOVE_REQUEST, - args_in, - "(s)", - &out); - - if (ret != VSMCLIENT_SUCCESS) { - return ret; - } - const gchar* retcode = NULL;; - g_variant_get(out, "(&s)", &retcode); - if (strcmp(retcode, api::zone::FILE_MOVE_SUCCEEDED.c_str()) != 0) { - mStatus = Status(VSMCLIENT_CUSTOM_ERROR, retcode); - g_variant_unref(out); - return vsm_get_status(); - } - g_variant_unref(out); - return ret; + return coverException([&] { + api::FileMoveRequestStatus status; + mZoneClient.callFileMoveRequest({ destZone, path }, status); + if (status.value != api::zone::FILE_MOVE_SUCCEEDED) { + throw ClientException(status.value); + } + }); } VsmStatus Client::vsm_add_notification_callback(VsmNotificationCallback notificationCallback, - void* data, - VsmSubscriptionId* subscriptionId) noexcept + void* data, + VsmSubscriptionId* subscriptionId) noexcept { assert(notificationCallback); - auto onSigal = [=](GVariant * parameters) { - const char* zone; - const char* application; - const char* message; - g_variant_get(parameters, "(&s&s&s)", &zone, &application, &message); - notificationCallback(zone, application, message, data); - }; - - return signalSubscribe(ZONE_INTERFACE, - api::zone::SIGNAL_NOTIFICATION, - onSigal, - subscriptionId); + return coverException([&] { + auto onSignal = [=](const api::Notification& notification) + { + notificationCallback(notification.zone.c_str(), + notification.application.c_str(), + notification.message.c_str(), + data); + }; + + VsmSubscriptionId id; + id = mZoneClient.subscribeNotification(onSignal); + if (subscriptionId) { + *subscriptionId = id; + } + }); } VsmStatus Client::vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept { - return signalUnsubscribe(subscriptionId); + return coverException([&] { + mZoneClient.unsubscribe(subscriptionId); + }); } diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 4e01966..634b801 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -27,26 +27,12 @@ #define VASUM_CLIENT_IMPL_HPP #include "vasum-client.h" -#include -#include -#include -#include -#include -/** - * Structure which defines the dbus interface. - */ -struct DbusInterfaceInfo { - DbusInterfaceInfo(const std::string& busName, - const std::string& objectPath, - const std::string& interface) - : busName(busName), - objectPath(objectPath), - interface(interface) {} - const std::string busName; - const std::string objectPath; - const std::string interface; -}; +#include "host-dbus-connection.hpp" +#include "zone-dbus-connection.hpp" + +#include +#include /** * vasum's client definition. @@ -54,33 +40,6 @@ struct DbusInterfaceInfo { * Client uses dbus API. */ class Client { -private: - typedef std::vector> NetdevAttrs; - typedef std::function SignalCallback; - struct Status { - Status(); - Status(VsmStatus status, const std::string& msg); - VsmStatus mVsmStatus; - std::string mMsg; - }; - - dbus::DbusConnection::Pointer mConnection; - Status mStatus; - - VsmStatus callMethod(const DbusInterfaceInfo& info, - const std::string& method, - GVariant* args_in, - const std::string& args_spec_out = std::string(), - GVariant** args_out = NULL); - VsmStatus signalSubscribe(const DbusInterfaceInfo& info, - const std::string& name, - SignalCallback signalCallback, - VsmSubscriptionId* subscriptionId); - VsmStatus signalUnsubscribe(VsmSubscriptionId id); - VsmStatus getNetdevAttrs(const std::string& zone, - const std::string& netdev, - NetdevAttrs& attrs) noexcept; - public: Client() noexcept; ~Client() noexcept; @@ -323,12 +282,12 @@ public: /** * @see ::vsm_list_declarations */ - VsmStatus vsm_list_declarations(const char* zone, VsmArrayString* declarations); + VsmStatus vsm_list_declarations(const char* zone, VsmArrayString* declarations) noexcept; /** * @see ::vsm_remove_declaration */ - VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration); + VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration) noexcept; /** * @see ::vsm_notify_active_zone @@ -361,6 +320,23 @@ public: * @see ::vsm_stop_glib_loop */ static VsmStatus vsm_stop_glib_loop() noexcept; +private: + struct Status { + Status(); + Status(VsmStatus status, const std::string& msg = ""); + VsmStatus mVsmStatus; + std::string mMsg; + }; + + Status mStatus; + vasum::client::HostDbusConnection mHostClient; + vasum::client::ZoneDbusConnection mZoneClient; + + VsmStatus coverException(const std::function worker) noexcept; + VsmStatus vsm_netdev_get_ip_addr(const char* zone, + const char* netdevId, + int type, + void* addr) noexcept; }; #endif /* VASUM_CLIENT_IMPL_HPP */ diff --git a/client/zone-dbus-connection.cpp b/client/zone-dbus-connection.cpp new file mode 100644 index 0000000..b7f82a8 --- /dev/null +++ b/client/zone-dbus-connection.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Zone client class + */ + +#include +#include "zone-dbus-connection.hpp" +#include +#include + +namespace vasum { +namespace client { + +ZoneDbusConnection::ZoneDbusConnection() + : mConnection(vasum::api::zone::DEFINITION, + vasum::api::zone::BUS_NAME, + vasum::api::zone::OBJECT_PATH, + vasum::api::zone::INTERFACE) +{ +} + +void ZoneDbusConnection::create(const std::shared_ptr& connection) +{ + mConnection.create(connection); +} + +void ZoneDbusConnection::callNotifyActiveZone(const vasum::api::NotifActiveZoneIn& argIn) +{ + mConnection.call(vasum::api::zone::METHOD_NOTIFY_ACTIVE_ZONE, argIn); +} + +void ZoneDbusConnection::callFileMoveRequest(const vasum::api::FileMoveRequestIn& argIn, + vasum::api::FileMoveRequestStatus& argOut) +{ + mConnection.call(vasum::api::zone::METHOD_FILE_MOVE_REQUEST, argIn, argOut); +} + +ZoneDbusConnection::SubscriptionId +ZoneDbusConnection::subscribeNotification(const NotificationCallback& callback) +{ + return mConnection.signalSubscribe( + vasum::api::zone::SIGNAL_NOTIFICATION, callback); +} + +void ZoneDbusConnection::unsubscribe(const SubscriptionId& id ) +{ + mConnection.signalUnsubscribe(id); +} + +} // namespace client +} // namespace vasum diff --git a/client/zone-dbus-connection.hpp b/client/zone-dbus-connection.hpp new file mode 100644 index 0000000..576b4cb --- /dev/null +++ b/client/zone-dbus-connection.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Zone client class + */ + +#ifndef VASUM_CLIENT_ZONE_DBUS_CONNECTION_HPP +#define VASUM_CLIENT_ZONE_DBUS_CONNECTION_HPP + +#include "dbus-connection.hpp" +#include + +namespace vasum { +namespace client { + +/** + * vasum's client definition. + * + * ZoneDbusConnection is used for communication with the vasum's server from zone through dbus + */ +class ZoneDbusConnection { +public: + typedef unsigned int SubscriptionId; + typedef std::function NotificationCallback; + + ZoneDbusConnection(); + void create(const std::shared_ptr& connection); + + void callNotifyActiveZone(const vasum::api::NotifActiveZoneIn& argIn); + void callFileMoveRequest(const vasum::api::FileMoveRequestIn& argIn, + vasum::api::FileMoveRequestStatus& argOut); + SubscriptionId subscribeNotification(const NotificationCallback& callback); + void unsubscribe(const SubscriptionId& id); +private: + DbusConnection mConnection; +}; + +} // namespace client +} // namespace vasum + +#endif /* VASUM_CLIENT_ZONE_DBUS_CONNECTION_HPP */ diff --git a/common/api/messages.hpp b/common/api/messages.hpp index de193bd..de606c0 100644 --- a/common/api/messages.hpp +++ b/common/api/messages.hpp @@ -84,6 +84,9 @@ typedef api::StringPair RemoveDeclarationIn; typedef api::StringPair CreateZoneIn; typedef api::StringPair RevokeDeviceIn; typedef api::StringPair DestroyNetDevIn; +typedef api::StringPair DbusState; +typedef api::StringPair NotifActiveZoneIn; +typedef api::StringPair FileMoveRequestIn; typedef api::VectorOfStrings ZoneIds; typedef api::VectorOfStrings Declarations; typedef api::VectorOfStrings NetDevList; @@ -223,6 +226,20 @@ struct GrantDeviceIn ) }; +struct Notification +{ + std::string zone; + std::string application; + std::string message; + + CONFIG_REGISTER + ( + zone, + application, + message + ) +}; + } // namespace api } // namespace vasum -- 2.7.4 From fb166c64324481b35f4cba2386691e6a2fd93258 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 10 Apr 2015 15:08:30 +0200 Subject: [PATCH 09/16] Zones stopped by default when Vasum is starting. [Bug/Feature] Zones was always started. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run server. Change-Id: I5ca9ad8bdedea43a409d8f1c9061447c6462c4cc Signed-off-by: Dariusz Michaluk --- server/server.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/server.cpp b/server/server.cpp index c2ca778..2271f08 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -107,7 +107,8 @@ void Server::run(bool asRoot) utils::ScopedGlibLoop loop; ZonesManager manager(mConfigPath); - manager.restoreAll(); + // Do not restore zones state at Vasum start + // manager.restoreAll(); LOGI("Daemon started"); gSignalLatch.wait(); -- 2.7.4 From f93b8129e0803f8c8374bbda05bc6630e67c63cd Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Thu, 9 Apr 2015 10:33:31 +0200 Subject: [PATCH 10/16] Host to host communication through IPC (switch to IPC #2) [Feature] Using IPC for host to host communication [Cause] Switching from Dbus to IPC [Solution] Using IPC in host and client [Verification] run ClientSuite tests with Valgrind Change-Id: I45bda31482fbf0a6a1dab7d14cc407bfd73a96c1 --- CMakeLists.txt | 2 + client/CMakeLists.txt | 19 +- client/host-ipc-connection.cpp | 183 ++++++++++++++ client/host-ipc-connection.hpp | 80 ++++++ client/ipc-connection.cpp | 47 ++++ client/ipc-connection.hpp | 90 +++++++ client/vasum-client-impl.cpp | 11 +- client/vasum-client-impl.hpp | 18 +- common/ipc/service.cpp | 14 +- ...ost-connection.cpp => host-dbus-connection.cpp} | 81 +++--- ...ost-connection.hpp => host-dbus-connection.hpp} | 17 +- server/host-ipc-connection.cpp | 272 +++++++++++++++++++++ server/host-ipc-connection.hpp | 119 +++++++++ server/host-ipc-definitions.hpp | 68 ++++++ server/zones-manager.cpp | 12 +- server/zones-manager.hpp | 11 +- 16 files changed, 977 insertions(+), 67 deletions(-) create mode 100644 client/host-ipc-connection.cpp create mode 100644 client/host-ipc-connection.hpp create mode 100644 client/ipc-connection.cpp create mode 100644 client/ipc-connection.hpp rename server/{host-connection.cpp => host-dbus-connection.cpp} (83%) rename server/{host-connection.hpp => host-dbus-connection.hpp} (97%) create mode 100644 server/host-ipc-connection.cpp create mode 100644 server/host-ipc-connection.hpp create mode 100644 server/host-ipc-definitions.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 743860b..e7f7aff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,8 @@ ADD_DEFINITIONS(-DVASUM_USER="${VASUM_USER}") ADD_DEFINITIONS(-DINPUT_EVENT_GROUP="${INPUT_EVENT_GROUP}") ADD_DEFINITIONS(-DDISK_GROUP="${DISK_GROUP}") ADD_DEFINITIONS(-DTTY_GROUP="${TTY_GROUP}") +ADD_DEFINITIONS(-DHOST_IPC_SOCKET="/var/run/vasum-ipc.socket") +#ADD_DEFINITIONS(-DDBUS_CONNECTION) ## Python packages directory ################################################### IF(NOT DEFINED PYTHON_SITELIB) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7198610..0ebbf75 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -25,7 +25,17 @@ FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/callback-guard.hpp ${COMMON_FOLDER}/utils/glib-loop.cpp ${COMMON_FOLDER}/utils/glib-loop.hpp ${COMMON_FOLDER}/base-exception.hpp - ${COMMON_FOLDER}/base-exception.cpp) + ${COMMON_FOLDER}/base-exception.cpp + ${COMMON_FOLDER}/utils/eventfd.hpp + ${COMMON_FOLDER}/utils/eventfd.cpp + ${COMMON_FOLDER}/utils/fd-utils.hpp + ${COMMON_FOLDER}/utils/fd-utils.cpp + ${COMMON_FOLDER}/epoll/*.hpp + ${COMMON_FOLDER}/epoll/*.cpp + ${COMMON_FOLDER}/ipc/*.hpp + ${COMMON_FOLDER}/ipc/*.cpp + ${COMMON_FOLDER}/ipc/internals/*.hpp + ${COMMON_FOLDER}/ipc/internals/*.cpp) SET(_LIB_VERSION_ "0.0.1") SET(_LIB_SOVERSION_ "0") @@ -44,11 +54,12 @@ SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY VERSION ${_LIB_VERSION_}) ## Link libraries ############################################################## -PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger libConfig) -INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS}) +FIND_PACKAGE(Boost COMPONENTS system filesystem) +PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger libConfig libsystemd-daemon) +INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES}) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/client/host-ipc-connection.cpp b/client/host-ipc-connection.cpp new file mode 100644 index 0000000..6a22e6b --- /dev/null +++ b/client/host-ipc-connection.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief HostIPCConnection class + */ + +#include +#include "host-ipc-connection.hpp" +#include +#include + +namespace vasum { +namespace client { + +void HostIPCConnection::createSystem() +{ + mConnection.createSystem(); +} + +void HostIPCConnection::callGetZoneIds(vasum::api::ZoneIds& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_ID_LIST, argOut); +} + +void HostIPCConnection::callGetActiveZoneId(vasum::api::ZoneId& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ACTIVE_ZONE_ID, argOut); +} + +void HostIPCConnection::callSetActiveZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SET_ACTIVE_ZONE, argIn); +} + +void HostIPCConnection::callGetZoneInfo(const vasum::api::ZoneId& argIn, vasum::api::ZoneInfoOut& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_INFO, argIn, argOut); +} + +void HostIPCConnection::callSetNetdevAttrs(const vasum::api::SetNetDevAttrsIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SET_NETDEV_ATTRS, argIn); +} + +void HostIPCConnection::callGetNetdevAttrs(const vasum::api::GetNetDevAttrsIn& argIn, vasum::api::GetNetDevAttrs& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_NETDEV_ATTRS, argIn, argOut); +} + +void HostIPCConnection::callGetNetdevList(const vasum::api::ZoneId& argIn, vasum::api::NetDevList& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_NETDEV_LIST, argIn, argOut); +} + +void HostIPCConnection::callCreateNetdevVeth(const vasum::api::CreateNetDevVethIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_VETH, argIn); +} + +void HostIPCConnection::callCreateNetdevMacvlan(const vasum::api::CreateNetDevMacvlanIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_MACVLAN, argIn); +} + +void HostIPCConnection::callCreateNetdevPhys(const vasum::api::CreateNetDevPhysIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_NETDEV_PHYS, argIn); +} + +void HostIPCConnection::callDestroyNetdev(const vasum::api::DestroyNetDevIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DESTROY_NETDEV, argIn); +} + +void HostIPCConnection::callDeleteNetdevIpAddress(const vasum::api::DeleteNetdevIpAddressIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, argIn); +} + +void HostIPCConnection::callDeclareFile(const vasum::api::DeclareFileIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_FILE, argIn, argOut); +} + +void HostIPCConnection::callDeclareMount(const vasum::api::DeclareMountIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_MOUNT, argIn, argOut); +} + +void HostIPCConnection::callDeclareLink(const vasum::api::DeclareLinkIn& argIn, vasum::api::Declaration& argOut) +{ + mConnection.call(vasum::api::host::METHOD_DECLARE_LINK, argIn, argOut); +} + +void HostIPCConnection::callGetDeclarations(const vasum::api::ZoneId& argIn, vasum::api::Declarations& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_DECLARATIONS, argIn, argOut); +} + +void HostIPCConnection::callRemoveDeclaration(const vasum::api::RemoveDeclarationIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_REMOVE_DECLARATION, argIn); +} + +void HostIPCConnection::callCreateZone(const vasum::api::CreateZoneIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_CREATE_ZONE, argIn); +} + +void HostIPCConnection::callDestroyZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_DESTROY_ZONE, argIn); +} + +void HostIPCConnection::callShutdownZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_SHUTDOWN_ZONE, argIn); +} + +void HostIPCConnection::callStartZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_START_ZONE, argIn); +} + +void HostIPCConnection::callLockZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_LOCK_ZONE, argIn); +} + +void HostIPCConnection::callUnlockZone(const vasum::api::ZoneId& argIn) +{ + mConnection.call(vasum::api::host::METHOD_UNLOCK_ZONE, argIn); +} + +void HostIPCConnection::callGrantDevice(const vasum::api::GrantDeviceIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_GRANT_DEVICE, argIn); +} + +void HostIPCConnection::callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn) +{ + mConnection.call(vasum::api::host::METHOD_REVOKE_DEVICE, argIn); +} + +void HostIPCConnection::callGetZoneDbuses(vasum::api::Dbuses& argOut) +{ + mConnection.call(vasum::api::host::METHOD_GET_ZONE_DBUSES, argOut); +} + +HostIPCConnection::SubscriptionId +HostIPCConnection::subscribeZoneDbusState(const ZoneDbusStateCallback& callback) +{ + mConnection.subscribe( + vasum::api::host::SIGNAL_ZONE_DBUS_STATE, callback); + return vasum::api::host::SIGNAL_ZONE_DBUS_STATE; +} + +void HostIPCConnection::unsubscribe(const SubscriptionId& id) +{ + mConnection.unsubscribe(id); +} + +} // namespace client +} // namespace vasum diff --git a/client/host-ipc-connection.hpp b/client/host-ipc-connection.hpp new file mode 100644 index 0000000..83313e1 --- /dev/null +++ b/client/host-ipc-connection.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief HostIPCConnection class + */ + +#ifndef VASUM_CLIENT_HOST_IPC_CONNECTION_HPP +#define VASUM_CLIENT_HOST_IPC_CONNECTION_HPP + +#include "ipc-connection.hpp" +#include + +namespace vasum { +namespace client { + +/** + * HostIPCConnection is used for communication with the vasum's server from host through ipc + */ +class HostIPCConnection { +public: + typedef unsigned int SubscriptionId; + typedef std::function ZoneDbusStateCallback; + void createSystem(); + + void callGetZoneIds(vasum::api::ZoneIds& argOut); + void callGetActiveZoneId(vasum::api::ZoneId& argOut); + void callSetActiveZone(const vasum::api::ZoneId& argIn); + void callGetZoneInfo(const vasum::api::ZoneId& argIn, vasum::api::ZoneInfoOut& argOut); + void callSetNetdevAttrs(const vasum::api::SetNetDevAttrsIn& argIn); + void callGetNetdevAttrs(const vasum::api::GetNetDevAttrsIn& argIn, vasum::api::GetNetDevAttrs& argOut); + void callGetNetdevList(const vasum::api::ZoneId& argIn, vasum::api::NetDevList& argOut); + void callCreateNetdevVeth(const vasum::api::CreateNetDevVethIn& argIn); + void callCreateNetdevMacvlan(const vasum::api::CreateNetDevMacvlanIn& argIn); + void callCreateNetdevPhys(const vasum::api::CreateNetDevPhysIn& argIn); + void callDestroyNetdev(const vasum::api::DestroyNetDevIn& argIn); + void callDeleteNetdevIpAddress(const vasum::api::DeleteNetdevIpAddressIn& argIn); + void callDeclareFile(const vasum::api::DeclareFileIn& argIn, vasum::api::Declaration& argOut); + void callDeclareMount(const vasum::api::DeclareMountIn& argIn, vasum::api::Declaration& argOut); + void callDeclareLink(const vasum::api::DeclareLinkIn& argIn, vasum::api::Declaration& argOut); + void callGetDeclarations(const vasum::api::ZoneId& argIn, vasum::api::Declarations& argOut); + void callRemoveDeclaration(const vasum::api::RemoveDeclarationIn& argIn); + void callCreateZone(const vasum::api::CreateZoneIn& argIn); + void callDestroyZone(const vasum::api::ZoneId& argIn); + void callShutdownZone(const vasum::api::ZoneId& argIn); + void callStartZone(const vasum::api::ZoneId& argIn); + void callLockZone(const vasum::api::ZoneId& argIn); + void callUnlockZone(const vasum::api::ZoneId& argIn); + void callGrantDevice(const vasum::api::GrantDeviceIn& argIn); + void callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn); + void callGetZoneDbuses(vasum::api::Dbuses& argOut); + SubscriptionId subscribeZoneDbusState(const ZoneDbusStateCallback& callback); + void unsubscribe(const SubscriptionId& id); + +private: + IPCConnection mConnection; +}; + +} // namespace client +} // namespace vasum + +#endif /* VASUM_CLIENT_HOST_IPC_CONNECTION_HPP */ diff --git a/client/ipc-connection.cpp b/client/ipc-connection.cpp new file mode 100644 index 0000000..04954bc --- /dev/null +++ b/client/ipc-connection.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief IPCConnection class + */ + +#include +#include "ipc-connection.hpp" + +namespace { + +const std::string SOCKET_PATH = HOST_IPC_SOCKET; + +} // namespace + +vasum::client::IPCConnection::IPCConnection() +{ +} + +vasum::client::IPCConnection::~IPCConnection() +{ +} + +void vasum::client::IPCConnection::createSystem() +{ + mClient.reset(new ipc::Client(mDispatcher.getPoll(), SOCKET_PATH)); + mClient->start(); +} diff --git a/client/ipc-connection.hpp b/client/ipc-connection.hpp new file mode 100644 index 0000000..1cb4d10 --- /dev/null +++ b/client/ipc-connection.hpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief IPCConnection class + */ + +#ifndef VASUM_CLIENT_IPC_CONNECTION_HPP +#define VASUM_CLIENT_IPC_CONNECTION_HPP + +#include +#include +#include +#include +#include +#include + +namespace vasum { +namespace client { + +/** + * IPCConnection class + */ +class IPCConnection { +public: + IPCConnection(); + virtual ~IPCConnection(); + + void createSystem(); + + template + typename std::enable_if::value>::type + call(const ipc::MethodID method, const ArgIn& argIn, ArgOut& argOut, unsigned int timeout = 50000) { + auto out = mClient->callSync(method, std::make_shared(argIn), timeout); + argOut = *out; + } + + template + typename std::enable_if::value>::type + call(const ipc::MethodID method, ArgOut& argOut, unsigned int timeout = 50000) { + vasum::api::Void argIn; + call(method, argIn, argOut, timeout); + } + + template + typename std::enable_if::value>::type + call(const ipc::MethodID method, ArgIn& argIn, unsigned int timeout = 50000) { + vasum::api::Void argOut; + call(method, argIn, argOut, timeout); + } + + template + void subscribe(const ipc::MethodID signal, const Callback& callback) { + auto callbackWrapper = [callback] (const ipc::PeerID, std::shared_ptr& data) { + callback(*data); + }; + mClient->setSignalHandler(signal, callbackWrapper); + } + + void unsubscribe(const ipc::MethodID signal) { + mClient->removeMethod(signal); + } + +private: + epoll::ThreadDispatcher mDispatcher; + std::unique_ptr mClient; +}; + +} // namespace client +} // namespace vasum + +#endif /* VASUM_CLIENT_IPC_CONNECTION_HPP */ diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 41a0030..2d85fb0 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -28,6 +28,7 @@ #include "utils.hpp" #include "exception.hpp" #include "host-dbus-connection.hpp" +#include "host-ipc-connection.hpp" #include "zone-dbus-connection.hpp" #include @@ -182,7 +183,7 @@ Client::~Client() noexcept { } -VsmStatus Client::coverException(const function worker) noexcept +VsmStatus Client::coverException(const function& worker) noexcept { try { worker(); @@ -218,7 +219,11 @@ VsmStatus Client::createSystem() noexcept return coverException([&] { shared_ptr connection(dbus::DbusConnection::createSystem().release()); +#ifdef DBUS_CONNECTION mHostClient.create(connection); +#else + mHostClient.createSystem(); +#endif mZoneClient.create(connection); }); } @@ -228,7 +233,11 @@ VsmStatus Client::create(const string& address) noexcept return coverException([&] { shared_ptr connection(dbus::DbusConnection::create(address).release()); +#ifdef DBUS_CONNECTION mHostClient.create(connection); +#else + mHostClient.createSystem(); +#endif mZoneClient.create(connection); }); } diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 634b801..9e8118c 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -27,8 +27,11 @@ #define VASUM_CLIENT_IMPL_HPP #include "vasum-client.h" - +#ifdef DBUS_CONNECTION #include "host-dbus-connection.hpp" +#else +#include "host-ipc-connection.hpp" +#endif #include "zone-dbus-connection.hpp" #include @@ -321,6 +324,12 @@ public: */ static VsmStatus vsm_stop_glib_loop() noexcept; private: +#ifdef DBUS_CONNECTION + typedef vasum::client::HostDbusConnection HostConnection; +#else + typedef vasum::client::HostIPCConnection HostConnection; +#endif + typedef vasum::client::ZoneDbusConnection ZoneConnection; struct Status { Status(); Status(VsmStatus status, const std::string& msg = ""); @@ -329,10 +338,11 @@ private: }; Status mStatus; - vasum::client::HostDbusConnection mHostClient; - vasum::client::ZoneDbusConnection mZoneClient; - VsmStatus coverException(const std::function worker) noexcept; + HostConnection mHostClient; + ZoneConnection mZoneClient; + + VsmStatus coverException(const std::function& worker) noexcept; VsmStatus vsm_netdev_get_ip_addr(const char* zone, const char* netdevId, int type, diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index 849ce3c..d4e1b88 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -100,13 +100,17 @@ void Service::handle(const FileDescriptor fd, const epoll::Events pollEvents) return; } - if (pollEvents & EPOLLIN) { - mProcessor.handleInput(fd); - return; // because handleInput will handle RDHUP - } - if ((pollEvents & EPOLLHUP) || (pollEvents & EPOLLRDHUP)) { + //IN, HUP, RDHUP are set when client is disconnecting but there is 0 bytes to read, so + //assume that if IN and HUP or RDHUP are set then input data is garbage. + //Assumption is harmless because handleInput processes all message data. mProcessor.handleLostConnection(fd); + return; + } + + if (pollEvents & EPOLLIN) { + //Process all message data + mProcessor.handleInput(fd); } } diff --git a/server/host-connection.cpp b/server/host-dbus-connection.cpp similarity index 83% rename from server/host-connection.cpp rename to server/host-dbus-connection.cpp index 1bdd790..b3eb19d 100644 --- a/server/host-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -24,7 +24,7 @@ #include "config.hpp" -#include "host-connection.hpp" +#include "host-dbus-connection.hpp" #include "host-dbus-definitions.hpp" #include "exception.hpp" #include "api/dbus-method-result-builder.hpp" @@ -45,7 +45,7 @@ const unsigned int NAME_ACQUIRED_TIMEOUT = 5 * 1000; } // namespace -HostConnection::HostConnection() +HostDbusConnection::HostDbusConnection() : mNameAcquired(false) , mNameLost(false) { @@ -54,8 +54,8 @@ HostConnection::HostConnection() LOGT("Setting DBUS name"); mDbusConnection->setName(api::host::BUS_NAME, - std::bind(&HostConnection::onNameAcquired, this), - std::bind(&HostConnection::onNameLost, this)); + std::bind(&HostDbusConnection::onNameAcquired, this), + std::bind(&HostDbusConnection::onNameLost, this)); if (!waitForName(NAME_ACQUIRED_TIMEOUT)) { LOGE("Could not acquire dbus name: " << api::host::BUS_NAME); @@ -66,17 +66,17 @@ HostConnection::HostConnection() using namespace std::placeholders; mDbusConnection->registerObject(api::host::OBJECT_PATH, api::host::DEFINITION, - std::bind(&HostConnection::onMessageCall, + std::bind(&HostDbusConnection::onMessageCall, this, _1, _2, _3, _4, _5)); LOGD("Connected"); } -HostConnection::~HostConnection() +HostDbusConnection::~HostDbusConnection() { } -bool HostConnection::waitForName(const unsigned int timeoutMs) +bool HostDbusConnection::waitForName(const unsigned int timeoutMs) { std::unique_lock lock(mNameMutex); mNameCondition.wait_for(lock, @@ -88,14 +88,14 @@ bool HostConnection::waitForName(const unsigned int timeoutMs) return mNameAcquired; } -void HostConnection::onNameAcquired() +void HostDbusConnection::onNameAcquired() { std::unique_lock lock(mNameMutex); mNameAcquired = true; mNameCondition.notify_one(); } -void HostConnection::onNameLost() +void HostDbusConnection::onNameLost() { std::unique_lock lock(mNameMutex); mNameLost = true; @@ -107,143 +107,143 @@ void HostConnection::onNameLost() } } -void HostConnection::setProxyCallCallback(const ProxyCallCallback& callback) +void HostDbusConnection::setProxyCallCallback(const ProxyCallCallback& callback) { mProxyCallCallback = callback; } -void HostConnection::setGetZoneDbusesCallback(const GetZoneDbusesCallback& callback) +void HostDbusConnection::setGetZoneDbusesCallback(const GetZoneDbusesCallback& callback) { mGetZoneDbusesCallback = callback; } -void HostConnection::setGetZoneIdsCallback(const GetZoneIdsCallback& callback) +void HostDbusConnection::setGetZoneIdsCallback(const GetZoneIdsCallback& callback) { mGetZoneIdsCallback = callback; } -void HostConnection::setGetActiveZoneIdCallback(const GetActiveZoneIdCallback& callback) +void HostDbusConnection::setGetActiveZoneIdCallback(const GetActiveZoneIdCallback& callback) { mGetActiveZoneIdCallback = callback; } -void HostConnection::setGetZoneInfoCallback(const GetZoneInfoCallback& callback) +void HostDbusConnection::setGetZoneInfoCallback(const GetZoneInfoCallback& callback) { mGetZoneInfoCallback = callback; } -void HostConnection::setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback) +void HostDbusConnection::setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback) { mSetNetdevAttrsCallback = callback; } -void HostConnection::setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback) +void HostDbusConnection::setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback) { mGetNetdevAttrsCallback = callback; } -void HostConnection::setGetNetdevListCallback(const GetNetdevListCallback& callback) +void HostDbusConnection::setGetNetdevListCallback(const GetNetdevListCallback& callback) { mGetNetdevListCallback = callback; } -void HostConnection::setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback) +void HostDbusConnection::setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback) { mCreateNetdevVethCallback = callback; } -void HostConnection::setCreateNetdevMacvlanCallback(const CreateNetdevMacvlanCallback& callback) +void HostDbusConnection::setCreateNetdevMacvlanCallback(const CreateNetdevMacvlanCallback& callback) { mCreateNetdevMacvlanCallback = callback; } -void HostConnection::setCreateNetdevPhysCallback(const CreateNetdevPhysCallback& callback) +void HostDbusConnection::setCreateNetdevPhysCallback(const CreateNetdevPhysCallback& callback) { mCreateNetdevPhysCallback = callback; } -void HostConnection::setDestroyNetdevCallback(const DestroyNetdevCallback& callback) +void HostDbusConnection::setDestroyNetdevCallback(const DestroyNetdevCallback& callback) { mDestroyNetdevCallback = callback; } -void HostConnection::setDeleleNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback) +void HostDbusConnection::setDeleteNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback) { mDeleteNetdevIpAddressCallback = callback; } -void HostConnection::setDeclareFileCallback(const DeclareFileCallback& callback) +void HostDbusConnection::setDeclareFileCallback(const DeclareFileCallback& callback) { mDeclareFileCallback = callback; } -void HostConnection::setDeclareMountCallback(const DeclareMountCallback& callback) +void HostDbusConnection::setDeclareMountCallback(const DeclareMountCallback& callback) { mDeclareMountCallback = callback; } -void HostConnection::setDeclareLinkCallback(const DeclareLinkCallback& callback) +void HostDbusConnection::setDeclareLinkCallback(const DeclareLinkCallback& callback) { mDeclareLinkCallback = callback; } -void HostConnection::setGetDeclarationsCallback(const GetDeclarationsCallback& callback) +void HostDbusConnection::setGetDeclarationsCallback(const GetDeclarationsCallback& callback) { mGetDeclarationsCallback = callback; } -void HostConnection::setRemoveDeclarationCallback(const RemoveDeclarationCallback& callback) +void HostDbusConnection::setRemoveDeclarationCallback(const RemoveDeclarationCallback& callback) { mRemoveDeclarationCallback = callback; } -void HostConnection::setSetActiveZoneCallback(const SetActiveZoneCallback& callback) +void HostDbusConnection::setSetActiveZoneCallback(const SetActiveZoneCallback& callback) { mSetActiveZoneCallback = callback; } -void HostConnection::setCreateZoneCallback(const CreateZoneCallback& callback) +void HostDbusConnection::setCreateZoneCallback(const CreateZoneCallback& callback) { mCreateZoneCallback = callback; } -void HostConnection::setDestroyZoneCallback(const DestroyZoneCallback& callback) +void HostDbusConnection::setDestroyZoneCallback(const DestroyZoneCallback& callback) { mDestroyZoneCallback = callback; } -void HostConnection::setShutdownZoneCallback(const ShutdownZoneCallback& callback) +void HostDbusConnection::setShutdownZoneCallback(const ShutdownZoneCallback& callback) { mShutdownZoneCallback = callback; } -void HostConnection::setStartZoneCallback(const StartZoneCallback& callback) +void HostDbusConnection::setStartZoneCallback(const StartZoneCallback& callback) { mStartZoneCallback = callback; } -void HostConnection::setLockZoneCallback(const LockZoneCallback& callback) +void HostDbusConnection::setLockZoneCallback(const LockZoneCallback& callback) { mLockZoneCallback = callback; } -void HostConnection::setUnlockZoneCallback(const UnlockZoneCallback& callback) +void HostDbusConnection::setUnlockZoneCallback(const UnlockZoneCallback& callback) { mUnlockZoneCallback = callback; } -void HostConnection::setGrantDeviceCallback(const GrantDeviceCallback& callback) +void HostDbusConnection::setGrantDeviceCallback(const GrantDeviceCallback& callback) { mGrantDeviceCallback = callback; } -void HostConnection::setRevokeDeviceCallback(const RevokeDeviceCallback& callback) +void HostDbusConnection::setRevokeDeviceCallback(const RevokeDeviceCallback& callback) { mRevokeDeviceCallback = callback; } -void HostConnection::onMessageCall(const std::string& objectPath, +void HostDbusConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, GVariant* parameters, @@ -553,7 +553,7 @@ void HostConnection::onMessageCall(const std::string& objectPath, } } -void HostConnection::proxyCallAsync(const std::string& busName, +void HostDbusConnection::proxyCallAsync(const std::string& busName, const std::string& objectPath, const std::string& interface, const std::string& method, @@ -569,10 +569,9 @@ void HostConnection::proxyCallAsync(const std::string& busName, callback); } -void HostConnection::signalZoneDbusState(const std::string& zoneId, - const std::string& dbusAddress) +void HostDbusConnection::signalZoneDbusState(const api::DbusState& state) { - GVariant* parameters = g_variant_new("(ss)", zoneId.c_str(), dbusAddress.c_str()); + GVariant* parameters = g_variant_new("(ss)", state.first.c_str(), state.second.c_str()); mDbusConnection->emitSignal(api::host::OBJECT_PATH, api::host::INTERFACE, api::host::SIGNAL_ZONE_DBUS_STATE, diff --git a/server/host-connection.hpp b/server/host-dbus-connection.hpp similarity index 97% rename from server/host-connection.hpp rename to server/host-dbus-connection.hpp index 4ad07c8..980b5e9 100644 --- a/server/host-connection.hpp +++ b/server/host-dbus-connection.hpp @@ -23,13 +23,14 @@ */ -#ifndef SERVER_HOST_CONNECTION_HPP -#define SERVER_HOST_CONNECTION_HPP +#ifndef SERVER_HOST_DBUS_CONNECTION_HPP +#define SERVER_HOST_DBUS_CONNECTION_HPP #include "dbus/connection.hpp" #include "api/method-result-builder.hpp" #include "api/messages.hpp" +#include #include #include #include @@ -39,11 +40,11 @@ namespace vasum { -class HostConnection { +class HostDbusConnection { public: - HostConnection(); - ~HostConnection(); + HostDbusConnection(); + ~HostDbusConnection(); // ------------- API -------------- @@ -144,7 +145,7 @@ public: /** * Send signal describing dbus address state change */ - void signalZoneDbusState(const std::string& zoneId, const std::string& dbusAddress); + void signalZoneDbusState(const api::DbusState& state); /** * Register a callback called to get a list of zone ids @@ -199,7 +200,7 @@ public: /** * Register a callback called to remove ip address from netdev */ - void setDeleleNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback); + void setDeleteNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback); /** * Register a callback called to declare file @@ -330,4 +331,4 @@ private: } // namespace vasum -#endif // SERVER_HOST_CONNECTION_HPP +#endif // SERVER_HOST_DBUS_CONNECTION_HPP diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp new file mode 100644 index 0000000..bb8d081 --- /dev/null +++ b/server/host-ipc-connection.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief HostIPCConnection class + */ + +#include "config.hpp" + +#include "host-ipc-connection.hpp" +#include "host-ipc-definitions.hpp" +#include "exception.hpp" +#include "logger/logger.hpp" + +namespace vasum { + +namespace { + +const std::string SOCKET_PATH = HOST_IPC_SOCKET; + +} // namespace + + +HostIPCConnection::HostIPCConnection() +{ + LOGT("Connecting to host IPC socket"); + mService.reset(new ipc::Service(mDispatcher.getPoll(), SOCKET_PATH)); + + LOGT("Starting IPC"); + mService->start(); + LOGD("Connected"); +} + +HostIPCConnection::~HostIPCConnection() +{ +} + +void HostIPCConnection::setGetZoneDbusesCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_ZONE_DBUSES, + Callback::getCallbackWrapper(callback)); + +} + +void HostIPCConnection::setGetZoneIdsCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_ZONE_ID_LIST, + Callback::getCallbackWrapper(callback)); + +} + +void HostIPCConnection::setGetActiveZoneIdCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_ACTIVE_ZONE_ID, + Callback::getCallbackWrapper(callback)); + +} + +void HostIPCConnection::setGetZoneInfoCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_ZONE_INFO, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setSetNetdevAttrsCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_SET_NETDEV_ATTRS, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setGetNetdevAttrsCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_NETDEV_ATTRS, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setGetNetdevListCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_NETDEV_LIST, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setCreateNetdevVethCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_CREATE_NETDEV_VETH, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setCreateNetdevMacvlanCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_CREATE_NETDEV_MACVLAN, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setCreateNetdevPhysCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_CREATE_NETDEV_PHYS, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDestroyNetdevCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DESTROY_NETDEV, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDeleteNetdevIpAddressCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DELETE_NETDEV_IP_ADDRESS, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDeclareFileCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DECLARE_FILE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDeclareMountCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DECLARE_MOUNT, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDeclareLinkCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DECLARE_LINK, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setGetDeclarationsCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GET_DECLARATIONS, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setRemoveDeclarationCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_REMOVE_DECLARATION, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setSetActiveZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_SET_ACTIVE_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setCreateZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_CREATE_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setDestroyZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_DESTROY_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setShutdownZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_SHUTDOWN_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setStartZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_START_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setLockZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_LOCK_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setUnlockZoneCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_UNLOCK_ZONE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setGrantDeviceCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_GRANT_DEVICE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::setRevokeDeviceCallback(const Callback::type& callback) +{ + typedef Callback Callback; + mService->setMethodHandler( + api::host::METHOD_REVOKE_DEVICE, + Callback::getCallbackWrapper(callback)); +} + +void HostIPCConnection::signalZoneDbusState(const api::DbusState& dbusState) +{ + mService->signal(api::host::SIGNAL_ZONE_DBUS_STATE, + std::make_shared(dbusState)); +} + +} // namespace vasum diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp new file mode 100644 index 0000000..e8c1c8d --- /dev/null +++ b/server/host-ipc-connection.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief HostIPCConnection class + */ + + +#ifndef SERVER_HOST_IPC_CONNECTION_HPP +#define SERVER_HOST_IPC_CONNECTION_HPP + +#include "api/messages.hpp" +#include "api/method-result-builder.hpp" +#include "api/ipc-method-result-builder.hpp" +#include "epoll/thread-dispatcher.hpp" +#include "ipc/service.hpp" + +#include + +namespace vasum { + + + +class HostIPCConnection { +public: + template + class Callback { + public: + typedef typename std::remove_cv::type in; + typedef ArgOut out; + typedef std::function type; + + static typename ipc::MethodHandler::type + getCallbackWrapper(const type& callback) { + return [callback](const ipc::PeerID, + const std::shared_ptr& argIn, + ipc::MethodResult::Pointer&& argOut) + { + auto rb = std::make_shared(argOut); + callback(*argIn, rb); + }; + } + }; + + template + class Callback::value, api::Void>::type> { + public: + typedef api::Void in; + typedef ArgOut out; + typedef std::function type; + + static typename ipc::MethodHandler::type + getCallbackWrapper(const type& callback) { + return [callback](const ipc::PeerID, + const std::shared_ptr& /* argIn */, + ipc::MethodResult::Pointer&& argOut) + { + auto rb = std::make_shared(argOut); + callback(rb); + }; + } + }; + + HostIPCConnection(); + ~HostIPCConnection(); + + void setGetZoneDbusesCallback(const Callback::type& callback); + void setGetZoneIdsCallback(const Callback::type& callback); + void setGetActiveZoneIdCallback(const Callback::type& callback); + void setGetZoneInfoCallback(const Callback::type& callback); + void setSetNetdevAttrsCallback(const Callback::type& callback); + void setGetNetdevAttrsCallback(const Callback::type& callback); + void setGetNetdevListCallback(const Callback::type& callback); + void setCreateNetdevVethCallback(const Callback::type& callback); + void setCreateNetdevMacvlanCallback(const Callback::type& callback); + void setCreateNetdevPhysCallback(const Callback::type& callback); + void setDestroyNetdevCallback(const Callback::type& callback); + void setDeleteNetdevIpAddressCallback(const Callback::type& callback); + void setDeclareFileCallback(const Callback::type& callback); + void setDeclareMountCallback(const Callback::type& callback); + void setDeclareLinkCallback(const Callback::type& callback); + void setGetDeclarationsCallback(const Callback::type& callback); + void setRemoveDeclarationCallback(const Callback::type& callback); + void setSetActiveZoneCallback(const Callback::type& callback); + void setCreateZoneCallback(const Callback::type& callback); + void setDestroyZoneCallback(const Callback::type& callback); + void setShutdownZoneCallback(const Callback::type& callback); + void setStartZoneCallback(const Callback::type& callback); + void setLockZoneCallback(const Callback::type& callback); + void setUnlockZoneCallback(const Callback::type& callback); + void setGrantDeviceCallback(const Callback::type& callback); + void setRevokeDeviceCallback(const Callback::type& callback); + void signalZoneDbusState(const api::DbusState& dbusState); + +private: + epoll::ThreadDispatcher mDispatcher; + std::unique_ptr mService; +}; + +} // namespace vasum + +#endif // SERVER_HOST_IPC_CONNECTION_HPP diff --git a/server/host-ipc-definitions.hpp b/server/host-ipc-definitions.hpp new file mode 100644 index 0000000..4cd06e7 --- /dev/null +++ b/server/host-ipc-definitions.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Host ipc api definitions + */ + +#ifndef SERVER_HOST_IPC_DEFINITIONS_HPP +#define SERVER_HOST_IPC_DEFINITIONS_HPP + +#include "ipc/types.hpp" + +namespace vasum { +namespace api { +namespace host { + +const vasum::ipc::MethodID METHOD_GET_ZONE_DBUSES = 1; +const vasum::ipc::MethodID METHOD_GET_ZONE_ID_LIST = 2; +const vasum::ipc::MethodID METHOD_GET_ACTIVE_ZONE_ID = 3; +const vasum::ipc::MethodID METHOD_GET_ZONE_INFO = 4; +const vasum::ipc::MethodID METHOD_SET_NETDEV_ATTRS = 5; +const vasum::ipc::MethodID METHOD_GET_NETDEV_ATTRS = 6; +const vasum::ipc::MethodID METHOD_GET_NETDEV_LIST = 7; +const vasum::ipc::MethodID METHOD_CREATE_NETDEV_VETH = 8; +const vasum::ipc::MethodID METHOD_CREATE_NETDEV_MACVLAN = 9; +const vasum::ipc::MethodID METHOD_CREATE_NETDEV_PHYS = 10; +const vasum::ipc::MethodID METHOD_DELETE_NETDEV_IP_ADDRESS = 11; +const vasum::ipc::MethodID METHOD_DESTROY_NETDEV = 12; +const vasum::ipc::MethodID METHOD_DECLARE_FILE = 13; +const vasum::ipc::MethodID METHOD_DECLARE_MOUNT = 14; +const vasum::ipc::MethodID METHOD_DECLARE_LINK = 15; +const vasum::ipc::MethodID METHOD_GET_DECLARATIONS = 16; +const vasum::ipc::MethodID METHOD_REMOVE_DECLARATION = 17; +const vasum::ipc::MethodID METHOD_SET_ACTIVE_ZONE = 18; +const vasum::ipc::MethodID METHOD_CREATE_ZONE = 19; +const vasum::ipc::MethodID METHOD_DESTROY_ZONE = 20; +const vasum::ipc::MethodID METHOD_SHUTDOWN_ZONE = 21; +const vasum::ipc::MethodID METHOD_START_ZONE = 22; +const vasum::ipc::MethodID METHOD_LOCK_ZONE = 23; +const vasum::ipc::MethodID METHOD_UNLOCK_ZONE = 24; +const vasum::ipc::MethodID METHOD_GRANT_DEVICE = 25; +const vasum::ipc::MethodID METHOD_REVOKE_DEVICE = 26; + +const vasum::ipc::MethodID SIGNAL_ZONE_DBUS_STATE = 27; + +} // namespace host +} // namespace api +} // namespace vasum + + +#endif // SERVER_HOST_IPC_DEFINITIONS_HPP diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index d3e802b..11589bd 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -127,8 +127,10 @@ ZonesManager::ZonesManager(const std::string& configPath) mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules)); using namespace std::placeholders; +#ifdef DBUS_CONNECTION mHostConnection.setProxyCallCallback(bind(&ZonesManager::handleProxyCall, this, HOST_ID, _1, _2, _3, _4, _5, _6, _7)); +#endif mHostConnection.setGetZoneDbusesCallback(bind(&ZonesManager::handleGetZoneDbusesCall, this, _1)); @@ -163,7 +165,7 @@ ZonesManager::ZonesManager(const std::string& configPath) mHostConnection.setDestroyNetdevCallback(bind(&ZonesManager::handleDestroyNetdevCall, this, _1, _2)); - mHostConnection.setDeleleNetdevIpAddressCallback(bind(&ZonesManager::handleDeleteNetdevIpAddressCall, + mHostConnection.setDeleteNetdevIpAddressCallback(bind(&ZonesManager::handleDeleteNetdevIpAddressCall, this, _1, _2)); mHostConnection.setDeclareFileCallback(bind(&ZonesManager::handleDeclareFileCall, @@ -717,12 +719,16 @@ void ZonesManager::handleProxyCall(const std::string& caller, }; if (target == HOST_ID) { +#ifdef DBUS_CONNECTION mHostConnection.proxyCallAsync(targetBusName, targetObjectPath, targetInterface, targetMethod, parameters, asyncResultCallback); +#else + result->setError(api::ERROR_INVALID_ID, "Unsupported proxy call target"); +#endif return; } @@ -755,10 +761,10 @@ void ZonesManager::handleGetZoneDbusesCall(api::MethodResultBuilder::Pointer res result->set(dbuses); } -void ZonesManager::handleDbusStateChanged(const std::string& zoneId, +void ZonesManager::handleDbusStateChanged(const std::string& zoneId , const std::string& dbusAddress) { - mHostConnection.signalZoneDbusState(zoneId, dbusAddress); + mHostConnection.signalZoneDbusState({zoneId, dbusAddress}); } void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result) diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index f789595..84285f3 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -28,7 +28,11 @@ #include "zone.hpp" #include "zones-manager-config.hpp" -#include "host-connection.hpp" +#ifdef DBUS_CONNECTION +#include "host-dbus-connection.hpp" +#else +#include "host-ipc-connection.hpp" +#endif #include "input-monitor.hpp" #include "proxy-call-policy.hpp" #include "utils/worker.hpp" @@ -114,6 +118,11 @@ public: private: typedef std::recursive_mutex Mutex; typedef std::unique_lock Lock; +#ifdef DBUS_CONNECTION + typedef HostDbusConnection HostConnection; +#else + typedef HostIPCConnection HostConnection; +#endif utils::Worker::Pointer mWorker; Mutex mMutex; // used to protect mZones -- 2.7.4 From 0d6b2ea9111fa21372e05f85478617e7ab6c2493 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 13 Apr 2015 15:05:24 +0200 Subject: [PATCH 11/16] Host to host communication test fix (switch to IPC #3) [Feature] Repaired tests that uses host to host communication [Cause] Switching from Dbus to IPC [Solution] Using IPCAccessory instead DbusAccessory [Verification] run tests with Valgrind Change-Id: Ia326bd98559691a7f5d61925760c811b0f5ea9a4 --- tests/unit_tests/server/ut-zones-manager.cpp | 524 ++++++++++++++++++++++----- 1 file changed, 430 insertions(+), 94 deletions(-) diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index b140e6f..12a3dbe 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -28,7 +28,14 @@ #include "zones-manager.hpp" #include "zone-dbus-definitions.hpp" +#ifdef DBUS_CONNECTION #include "host-dbus-definitions.hpp" +#else +#include "host-ipc-definitions.hpp" +#include +#include +#include +#endif #include "test-dbus-definitions.hpp" // TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager #include "fake-power-manager-dbus-definitions.hpp" @@ -77,6 +84,7 @@ const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf const std::string SIMPLE_TEMPLATE = "console"; const std::string DBUS_TEMPLATE = "console-dbus"; +#ifdef DBUS_CONNECTION /** * Currently there is no way to propagate an error from async call * dropException are used to prevent system crash @@ -101,9 +109,19 @@ public: MethodResultBuilder::Pointer result )> TestApiMethodCallback; typedef std::function VoidResultCallback; + typedef std::function SignalCallback; typedef std::map Dbuses; + DbusAccessory() + : mId(0), + mClient(DbusConnection::create(acquireAddress())), + mNameAcquired(false), + mPendingDisconnect(false) + { + } + DbusAccessory(int id) : mId(id), mClient(DbusConnection::create(acquireAddress())), @@ -150,6 +168,26 @@ public: mClient->signalSubscribe(callback, isHost() ? api::host::BUS_NAME : api::zone::BUS_NAME); } + void subscribeZoneDbusState(const SignalCallback& callback) { + assert(isHost()); + auto onSignal = [callback] (const std::string& /*senderBusName*/, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant* parameters) { + if (objectPath == api::host::OBJECT_PATH && + interface == api::host::INTERFACE && + signalName == api::host::SIGNAL_ZONE_DBUS_STATE) { + + const gchar* zoneId = NULL; + const gchar* dbusAddress = NULL; + g_variant_get(parameters, "(&s&s)", &zoneId, &dbusAddress); + callback(zoneId, dbusAddress); + } + }; + mClient->signalSubscribe(onSignal, api::host::BUS_NAME); + } + void emitSignal(const std::string& objectPath, const std::string& interface, const std::string& name, @@ -451,6 +489,308 @@ private: } }; +typedef DbusAccessory HostAccessory; +typedef DbusAccessory ZoneAccessory; + +#else +//#ifdef DBUS_CONNECTION + +class HostIPCAccessory { +public: + typedef std::function TestApiMethodCallback; + typedef std::function VoidResultCallback; + typedef std::function SignalCallback; + + typedef std::map Dbuses; + + HostIPCAccessory() + : mClient(mDispatcher.getPoll(), HOST_IPC_SOCKET) + { + mClient.start(); + } + + void subscribeZoneDbusState(const SignalCallback& callback) + { + auto callbackWrapper = [callback] (const ipc::PeerID, std::shared_ptr& data) { + callback(data->first, data->second); + }; + mClient.setSignalHandler(api::host::SIGNAL_ZONE_DBUS_STATE, callbackWrapper); + } + + Dbuses callMethodGetZoneDbuses() + { + const auto out = mClient.callSync(api::host::METHOD_GET_ZONE_DBUSES, + std::make_shared()); + Dbuses dbuses; + for (const auto& dbus : out->values) { + dbuses.insert(Dbuses::value_type(dbus.first, dbus.second)); + } + return dbuses; + } + + std::vector callMethodGetZoneIds() + { + const auto out = mClient.callSync(api::host::METHOD_GET_ZONE_ID_LIST, + std::make_shared()); + return out->values; + } + + std::string callMethodGetActiveZoneId() + { + const auto out = mClient.callSync(api::host::METHOD_GET_ACTIVE_ZONE_ID, + std::make_shared()); + return out->value; + } + + void callMethodSetActiveZone(const std::string& id) + { + mClient.callSync(api::host::METHOD_SET_ACTIVE_ZONE, + std::make_shared(api::ZoneId{id})); + } + + void callAsyncMethodCreateZone(const std::string& id, + const std::string& templateName, + const VoidResultCallback& result) + { + auto asyncResult = [result](ipc::Result&& out) { + if (out.isValid()) { + result(); + } + }; + mClient.callAsync(api::host::METHOD_CREATE_ZONE, + std::make_shared(api::CreateZoneIn{id, templateName}), + asyncResult); + } + + void callAsyncMethodDestroyZone(const std::string& id, + const VoidResultCallback& result) + { + auto asyncResult = [result](ipc::Result&& out) { + if (out.isValid()) { + result(); + } + }; + mClient.callAsync(api::host::METHOD_DESTROY_ZONE, + std::make_shared(api::ZoneId{id}), + asyncResult); + } + + void callAsyncMethodShutdownZone(const std::string& id, + const VoidResultCallback& result) + { + auto asyncResult = [result](ipc::Result&& out) { + if (out.isValid()) { + result(); + } + }; + mClient.callAsync(api::host::METHOD_SHUTDOWN_ZONE, + std::make_shared(api::ZoneId{id}), + asyncResult); + } + + void callAsyncMethodStartZone(const std::string& id, + const VoidResultCallback& result) + { + auto asyncResult = [result](ipc::Result&& out) { + if (out.isValid()) { + result(); + } + }; + mClient.callAsync(api::host::METHOD_START_ZONE, + std::make_shared(api::ZoneId{id}), + asyncResult); + } + + void callMethodLockZone(const std::string& id) + { + mClient.callSync(api::host::METHOD_LOCK_ZONE, + std::make_shared(api::ZoneId{id}), + EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone + } + + void callMethodUnlockZone(const std::string& id) + { + mClient.callSync(api::host::METHOD_UNLOCK_ZONE, + std::make_shared(api::ZoneId{id}), + EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone + } + +private: + epoll::ThreadDispatcher mDispatcher; + ipc::Client mClient; +}; + +class ZoneDbusAccessory { +public: + typedef std::function TestApiMethodCallback; + + typedef std::map Dbuses; + + ZoneDbusAccessory(int id) + : mId(id), + mClient(DbusConnection::create(acquireAddress())), + mNameAcquired(false), + mPendingDisconnect(false) + { + } + + void setName(const std::string& name) + { + mClient->setName(name, + std::bind(&ZoneDbusAccessory::onNameAcquired, this), + std::bind(&ZoneDbusAccessory::onDisconnect, this)); + + if(!waitForName()) { + mClient.reset(); + throw dbus::DbusOperationException("Could not acquire name."); + } + } + + bool waitForName() + { + std::unique_lock lock(mMutex); + mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;}); + return mNameAcquired; + } + + void onNameAcquired() + { + std::unique_lock lock(mMutex); + mNameAcquired = true; + mNameCondition.notify_one(); + } + + void onDisconnect() + { + std::unique_lock lock(mMutex); + mPendingDisconnect = true; + mNameCondition.notify_one(); + } + + void signalSubscribe(const DbusConnection::SignalCallback& callback) + { + mClient->signalSubscribe(callback, api::zone::BUS_NAME); + } + + void emitSignal(const std::string& objectPath, + const std::string& interface, + const std::string& name, + GVariant* parameters) + { + mClient->emitSignal(objectPath, interface, name, parameters); + } + + void callMethodNotify() + { + GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSAGE.c_str()); + mClient->callMethod(api::zone::BUS_NAME, + api::zone::OBJECT_PATH, + api::zone::INTERFACE, + api::zone::METHOD_NOTIFY_ACTIVE_ZONE, + parameters, + "()"); + } + + std::string callMethodMove(const std::string& dest, const std::string& path) + { + GVariant* parameters = g_variant_new("(ss)", dest.c_str(), path.c_str()); + GVariantPtr result = mClient->callMethod(api::zone::BUS_NAME, + api::zone::OBJECT_PATH, + api::zone::INTERFACE, + api::zone::METHOD_FILE_MOVE_REQUEST, + parameters, + "(s)"); + + const gchar* retcode = NULL; + g_variant_get(result.get(), "(&s)", &retcode); + return std::string(retcode); + } + + void registerTestApiObject(const TestApiMethodCallback& callback) + { + auto handler = [callback](const std::string& objectPath, + const std::string& interface, + const std::string& methodName, + GVariant* parameters, + MethodResultBuilder::Pointer result) { + if (objectPath == testapi::OBJECT_PATH && + interface == testapi::INTERFACE && + methodName == testapi::METHOD) { + const gchar* argument = NULL; + g_variant_get(parameters, "(&s)", &argument); + if (callback) { + callback(argument, result); + } + } + }; + mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler); + } + + std::string testApiProxyCall(const std::string& target, const std::string& argument) + { + GVariant* parameters = g_variant_new("(s)", argument.c_str()); + GVariantPtr result = proxyCall(target, + testapi::BUS_NAME, + testapi::OBJECT_PATH, + testapi::INTERFACE, + testapi::METHOD, + parameters); + const gchar* ret = NULL; + g_variant_get(result.get(), "(&s)", &ret); + return ret; + } + + + GVariantPtr proxyCall(const std::string& target, + const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters) + { + GVariant* packedParameters = g_variant_new("(sssssv)", + target.c_str(), + busName.c_str(), + objectPath.c_str(), + interface.c_str(), + method.c_str(), + parameters); + GVariantPtr result = mClient->callMethod(api::zone::BUS_NAME, + api::zone::OBJECT_PATH, + api::zone::INTERFACE, + api::METHOD_PROXY_CALL, + packedParameters, + "(v)"); + GVariant* unpackedResult = NULL; + g_variant_get(result.get(), "(v)", &unpackedResult); + return GVariantPtr(unpackedResult, g_variant_unref); + } + +private: + const int mId; + DbusConnection::Pointer mClient; + bool mNameAcquired; + bool mPendingDisconnect; + std::mutex mMutex; + std::condition_variable mNameCondition; + + std::string acquireAddress() const + { + std::string zoneId = "zone" + std::to_string(mId); + return "unix:path=/tmp/ut-run/" + zoneId + "/dbus/system_bus_socket"; + } +}; + +typedef HostIPCAccessory HostAccessory; +typedef ZoneDbusAccessory ZoneAccessory; + +#endif //DBUS_CONNECTION + template bool spinWaitFor(int timeoutMs, Predicate pred) { @@ -559,9 +899,9 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZone) Latch signalReceivedLatch; std::map> signalReceivedSourcesMap; - std::map> dbuses; + std::map> dbuses; for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - dbuses[i] = std::unique_ptr(new DbusAccessory(i)); + dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); } auto handler = [](Latch& latch, @@ -626,9 +966,9 @@ BOOST_AUTO_TEST_CASE(DisplayOff) cm.createZone("zone3", DBUS_TEMPLATE); cm.restoreAll(); - std::vector> clients; + std::vector> clients; for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - clients.push_back(std::unique_ptr(new DbusAccessory(i))); + clients.push_back(std::unique_ptr(new ZoneAccessory(i))); } for (auto& client : clients) { @@ -668,9 +1008,9 @@ BOOST_AUTO_TEST_CASE(MoveFile) std::string notificationPath; std::string notificationRetcode; - std::map> dbuses; + std::map> dbuses; for (int i = 1; i <= 2; ++i) { - dbuses[i] = std::unique_ptr(new DbusAccessory(i)); + dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); } auto handler = [&](const std::string& /*senderBusName*/, @@ -765,9 +1105,9 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefault) cm.createZone("zone3", DBUS_TEMPLATE); cm.restoreAll(); - std::vector> clients; + std::vector> clients; for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - clients.push_back(std::unique_ptr(new DbusAccessory(i))); + clients.push_back(std::unique_ptr(new ZoneAccessory(i))); } for (auto& client : clients) { @@ -806,6 +1146,7 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefault) } } +#ifdef DBUS_CONNECTION BOOST_AUTO_TEST_CASE(ProxyCall) { ZonesManager cm(TEST_CONFIG_PATH); @@ -815,8 +1156,9 @@ BOOST_AUTO_TEST_CASE(ProxyCall) cm.restoreAll(); std::map> dbuses; - for (int i = 0; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - dbuses[i] = std::unique_ptr(new DbusAccessory(i)); + dbuses[0] = std::unique_ptr(new HostAccessory()); + for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { + dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); } for (auto& dbus : dbuses) { @@ -879,14 +1221,15 @@ BOOST_AUTO_TEST_CASE(ProxyCall) DbusCustomException, WhatEquals("Proxy call forbidden")); } +#endif // DBUS_CONNECTION namespace { - const DbusAccessory::Dbuses EXPECTED_DBUSES_NONE = { + const HostAccessory::Dbuses EXPECTED_DBUSES_NONE = { {"zone1", ""}, {"zone2", ""}, {"zone3", ""}}; - const DbusAccessory::Dbuses EXPECTED_DBUSES_ALL = { + const HostAccessory::Dbuses EXPECTED_DBUSES_ALL = { {"zone1", "unix:path=/tmp/ut-run/zone1/dbus/system_bus_socket"}, {"zone2", @@ -897,8 +1240,8 @@ namespace { BOOST_AUTO_TEST_CASE(GetZoneDbuses) { - DbusAccessory host(DbusAccessory::HOST_ID); ZonesManager cm(TEST_CONFIG_PATH); + HostAccessory host; cm.createZone("zone1", DBUS_TEMPLATE); cm.createZone("zone2", DBUS_TEMPLATE); cm.createZone("zone3", DBUS_TEMPLATE); @@ -912,8 +1255,8 @@ BOOST_AUTO_TEST_CASE(GetZoneDbuses) BOOST_AUTO_TEST_CASE(GetZoneDbusesNoDbus) { - DbusAccessory host(DbusAccessory::HOST_ID); ZonesManager cm(TEST_CONFIG_PATH); + HostAccessory host; cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -928,32 +1271,19 @@ BOOST_AUTO_TEST_CASE(GetZoneDbusesNoDbus) BOOST_AUTO_TEST_CASE(ZoneDbusesSignals) { Latch signalLatch; - DbusAccessory::Dbuses collectedDbuses; + HostAccessory::Dbuses collectedDbuses; + std::mutex collectedDbusesMutex; - DbusAccessory host(DbusAccessory::HOST_ID); - - auto onSignal = [&] (const std::string& /*senderBusName*/, - const std::string& objectPath, - const std::string& interface, - const std::string& signalName, - GVariant* parameters) { - if (objectPath == api::host::OBJECT_PATH && - interface == api::host::INTERFACE && - signalName == api::host::SIGNAL_ZONE_DBUS_STATE) { - - const gchar* zoneId = NULL; - const gchar* dbusAddress = NULL; - g_variant_get(parameters, "(&s&s)", &zoneId, &dbusAddress); - - collectedDbuses.insert(DbusAccessory::Dbuses::value_type(zoneId, dbusAddress)); - signalLatch.set(); - } + auto onSignal = [&] (const std::string& zoneId, const std::string& dbusAddress) { + std::unique_lock lock(collectedDbusesMutex); + collectedDbuses.insert(HostAccessory::Dbuses::value_type(zoneId, dbusAddress)); + signalLatch.set(); }; - host.signalSubscribe(onSignal); - { ZonesManager cm(TEST_CONFIG_PATH); + HostAccessory host; + host.subscribeZoneDbusState(onSignal); cm.createZone("zone1", DBUS_TEMPLATE); cm.createZone("zone2", DBUS_TEMPLATE); cm.createZone("zone3", DBUS_TEMPLATE); @@ -965,13 +1295,10 @@ BOOST_AUTO_TEST_CASE(ZoneDbusesSignals) BOOST_REQUIRE(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT)); BOOST_CHECK(signalLatch.empty()); + std::unique_lock lock(collectedDbusesMutex); BOOST_CHECK(EXPECTED_DBUSES_ALL == collectedDbuses); collectedDbuses.clear(); } - - BOOST_CHECK(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT)); - BOOST_CHECK(signalLatch.empty()); - BOOST_CHECK(EXPECTED_DBUSES_NONE == collectedDbuses); } @@ -982,12 +1309,12 @@ BOOST_AUTO_TEST_CASE(GetZoneIds) cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; std::vector zoneIds = {"zone1", "zone2", "zone3"}; - std::vector returnedIds = dbus.callMethodGetZoneIds(); + std::vector returnedIds = host.callMethodGetZoneIds(); BOOST_CHECK(returnedIds == zoneIds);// order should be preserved } @@ -1000,7 +1327,7 @@ BOOST_AUTO_TEST_CASE(GetActiveZoneId) cm.createZone("zone3", SIMPLE_TEMPLATE); cm.restoreAll(); - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; std::vector zoneIds = {"zone1", "zone2", @@ -1008,11 +1335,11 @@ BOOST_AUTO_TEST_CASE(GetActiveZoneId) for (const std::string& zoneId: zoneIds){ cm.focus(zoneId); - BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId); + BOOST_CHECK(host.callMethodGetActiveZoneId() == zoneId); } cm.shutdownAll(); - BOOST_CHECK(dbus.callMethodGetActiveZoneId() == ""); + BOOST_CHECK(host.callMethodGetActiveZoneId() == ""); } BOOST_AUTO_TEST_CASE(SetActiveZone) @@ -1023,24 +1350,24 @@ BOOST_AUTO_TEST_CASE(SetActiveZone) cm.createZone("zone3", SIMPLE_TEMPLATE); cm.restoreAll(); - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; std::vector zoneIds = {"zone1", "zone2", "zone3"}; for (const std::string& zoneId: zoneIds){ - dbus.callMethodSetActiveZone(zoneId); - BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId); + host.callMethodSetActiveZone(zoneId); + BOOST_CHECK(host.callMethodGetActiveZoneId() == zoneId); } - BOOST_REQUIRE_EXCEPTION(dbus.callMethodSetActiveZone(NON_EXISTANT_ZONE_ID), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodSetActiveZone(NON_EXISTANT_ZONE_ID), + std::exception, //TODO: exception should be more specific WhatEquals("No such zone id")); cm.shutdownAll(); - BOOST_REQUIRE_EXCEPTION(dbus.callMethodSetActiveZone("zone1"), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodSetActiveZone("zone1"), + std::exception, //TODO: exception should be more specific WhatEquals("Could not activate stopped or paused zone")); } @@ -1060,18 +1387,18 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZone) callDone.set(); }; - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; // create zone1 - dbus.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone2 - dbus.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // create zone3 - dbus.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); cm.restoreAll(); @@ -1081,17 +1408,17 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZone) BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone3); // destroy zone2 - dbus.callAsyncMethodDestroyZone(zone2, resultCallback); + host.callAsyncMethodDestroyZone(zone2, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone3); // destroy zone3 - dbus.callAsyncMethodDestroyZone(zone3, resultCallback); + host.callAsyncMethodDestroyZone(zone3, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1); // destroy zone1 - dbus.callAsyncMethodDestroyZone(zone1, resultCallback); + host.callAsyncMethodDestroyZone(zone1, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), ""); } @@ -1109,8 +1436,8 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistence) ZonesManager cm(TEST_CONFIG_PATH); cm.restoreAll(); - DbusAccessory dbus(DbusAccessory::HOST_ID); - return dbus.callMethodGetZoneIds(); + HostAccessory host; + return host.callMethodGetZoneIds(); }; BOOST_CHECK(getZoneIds().empty()); @@ -1118,8 +1445,8 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistence) // create zone { ZonesManager cm(TEST_CONFIG_PATH); - DbusAccessory dbus(DbusAccessory::HOST_ID); - dbus.callAsyncMethodCreateZone(zone, SIMPLE_TEMPLATE, resultCallback); + HostAccessory host; + host.callAsyncMethodCreateZone(zone, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } @@ -1132,8 +1459,8 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZonePersistence) // destroy zone { ZonesManager cm(TEST_CONFIG_PATH); - DbusAccessory dbus(DbusAccessory::HOST_ID); - dbus.callAsyncMethodDestroyZone(zone, resultCallback); + HostAccessory host; + host.callAsyncMethodDestroyZone(zone, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } @@ -1156,44 +1483,44 @@ BOOST_AUTO_TEST_CASE(ZoneStatePersistence) // firts run { ZonesManager cm(TEST_CONFIG_PATH); - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; // zone1 - created - dbus.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); // zone2 - started - dbus.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodStartZone(zone2, resultCallback); + host.callAsyncMethodStartZone(zone2, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(cm.isRunning(zone2)); // zone3 - started then paused - dbus.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodStartZone(zone3, resultCallback); + host.callAsyncMethodStartZone(zone3, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callMethodLockZone(zone3); + host.callMethodLockZone(zone3); BOOST_CHECK(cm.isPaused(zone3)); // zone4 - started then stopped - dbus.callAsyncMethodCreateZone(zone4, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone4, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodStartZone(zone4, resultCallback); + host.callAsyncMethodStartZone(zone4, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodShutdownZone(zone4, resultCallback); + host.callAsyncMethodShutdownZone(zone4, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(cm.isStopped(zone4)); // zone5 - started then stopped then started - dbus.callAsyncMethodCreateZone(zone5, SIMPLE_TEMPLATE, resultCallback); + host.callAsyncMethodCreateZone(zone5, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodStartZone(zone5, resultCallback); + host.callAsyncMethodStartZone(zone5, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodShutdownZone(zone5, resultCallback); + host.callAsyncMethodShutdownZone(zone5, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); - dbus.callAsyncMethodStartZone(zone5, resultCallback); + host.callAsyncMethodStartZone(zone5, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(cm.isRunning(zone5)); } @@ -1225,27 +1552,27 @@ BOOST_AUTO_TEST_CASE(StartShutdownZone) callDone.set(); }; - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; // start zone1 - dbus.callAsyncMethodStartZone(zone1, resultCallback); + host.callAsyncMethodStartZone(zone1, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(cm.isRunning(zone1)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1); // start zone2 - dbus.callAsyncMethodStartZone(zone2, resultCallback); + host.callAsyncMethodStartZone(zone2, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(cm.isRunning(zone2)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone2); // shutdown zone2 - dbus.callAsyncMethodShutdownZone(zone2, resultCallback); + host.callAsyncMethodShutdownZone(zone2, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(!cm.isRunning(zone2)); // shutdown zone1 - dbus.callAsyncMethodShutdownZone(zone1, resultCallback); + host.callAsyncMethodShutdownZone(zone1, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); BOOST_CHECK(!cm.isRunning(zone1)); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), ""); @@ -1259,32 +1586,41 @@ BOOST_AUTO_TEST_CASE(LockUnlockZone) cm.createZone("zone3", DBUS_TEMPLATE); cm.restoreAll(); - DbusAccessory dbus(DbusAccessory::HOST_ID); + HostAccessory host; std::vector zoneIds = {"zone1", "zone2", "zone3"}; for (const std::string& zoneId: zoneIds){ - dbus.callMethodLockZone(zoneId); + try { + host.callMethodLockZone(zoneId); + } catch(const std::exception&) { + //This try catch clause is for prevent from test crashing + //and should be removed after resolve following errors + //TODO: Abort when zone is locked on destroying ZonesManager + HostAccessory host2; //TODO: After IPCTimeoutException host is useless -- fix it + try { host2.callMethodUnlockZone(zoneId); } catch (...) {}; + throw; + } BOOST_CHECK(cm.isPaused(zoneId)); - dbus.callMethodUnlockZone(zoneId); + host.callMethodUnlockZone(zoneId); BOOST_CHECK(cm.isRunning(zoneId)); } - BOOST_REQUIRE_EXCEPTION(dbus.callMethodLockZone(NON_EXISTANT_ZONE_ID), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodLockZone(NON_EXISTANT_ZONE_ID), + std::exception, //TODO: exception should be more specific WhatEquals("No such zone id")); - BOOST_REQUIRE_EXCEPTION(dbus.callMethodUnlockZone(NON_EXISTANT_ZONE_ID), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodUnlockZone(NON_EXISTANT_ZONE_ID), + std::exception, //TODO: exception should be more specific WhatEquals("No such zone id")); cm.shutdownAll(); - BOOST_REQUIRE_EXCEPTION(dbus.callMethodLockZone("zone1"), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodLockZone("zone1"), + std::exception, //TODO: exception should be more specific WhatEquals("Zone is not running")); - BOOST_REQUIRE_EXCEPTION(dbus.callMethodUnlockZone("zone1"), - DbusException, + BOOST_REQUIRE_EXCEPTION(host.callMethodUnlockZone("zone1"), + std::exception, //TODO: exception should be more specific WhatEquals("Zone is not paused")); } -- 2.7.4 From 5a608e18a90ffb35171d5be56adbb540f7c918a5 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 14 Apr 2015 17:36:19 +0200 Subject: [PATCH 12/16] Add libSimpleDbus, libLogger, libConfig source code to Vasum. [Feature] Add libSimpleDbus, libLogger, libConfig source code to Vasum. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run server. Change-Id: I2466604ee744874237fb989695d4104d399cdca1 Signed-off-by: Dariusz Michaluk --- CMakeLists.txt | 1 + client/CMakeLists.txt | 27 +- client/dbus-connection.cpp | 2 +- client/dbus-connection.hpp | 6 +- common/api/method-result-builder.hpp | 2 +- common/config/exception.hpp | 44 +++ common/config/fdstore.cpp | 148 ++++++++ common/config/fdstore.hpp | 72 ++++ common/config/fields-union.hpp | 194 ++++++++++ common/config/fields.hpp | 85 +++++ common/config/from-fdstore-visitor.hpp | 91 +++++ common/config/from-gvariant-visitor.hpp | 167 +++++++++ common/config/from-json-visitor.hpp | 162 ++++++++ common/config/from-kvjson-visitor.hpp | 279 ++++++++++++++ common/config/from-kvstore-visitor.hpp | 92 +++++ common/config/fs-utils.cpp | 73 ++++ common/config/fs-utils.hpp | 43 +++ common/config/is-union.hpp | 70 ++++ common/config/is-visitable.hpp | 53 +++ common/config/kvstore.cpp | 342 +++++++++++++++++ common/config/kvstore.hpp | 261 +++++++++++++ common/config/manager.hpp | 257 +++++++++++++ common/config/sqlite3/connection.cpp | 77 ++++ common/config/sqlite3/connection.hpp | 66 ++++ common/config/sqlite3/statement.cpp | 77 ++++ common/config/sqlite3/statement.hpp | 66 ++++ common/config/to-fdstore-visitor.hpp | 88 +++++ common/config/to-gvariant-visitor.hpp | 126 +++++++ common/config/to-json-visitor.hpp | 140 +++++++ common/config/to-kvstore-visitor.hpp | 86 +++++ common/dbus/connection.cpp | 409 +++++++++++++++++++++ common/dbus/connection.hpp | 211 +++++++++++ common/dbus/exception.hpp | 74 ++++ common/ipc/client.hpp | 2 +- common/ipc/internals/processor.hpp | 2 +- common/ipc/service.hpp | 2 +- common/logger/backend-journal.cpp | 71 ++++ common/logger/backend-journal.hpp | 46 +++ common/logger/backend-null.hpp | 46 +++ common/logger/backend-stderr.cpp | 61 +++ common/logger/backend-stderr.hpp | 46 +++ common/logger/backend.hpp | 49 +++ common/logger/ccolor.cpp | 41 +++ common/logger/ccolor.hpp | 53 +++ common/logger/formatter.cpp | 131 +++++++ common/logger/formatter.hpp | 50 +++ common/logger/level.cpp | 71 ++++ common/logger/level.hpp | 55 +++ common/logger/logger-scope.cpp | 56 +++ common/logger/logger-scope.hpp | 78 ++++ common/logger/logger.cpp | 76 ++++ common/logger/logger.hpp | 79 ++++ common/netlink/netlink-message.hpp | 1 + common/utils/glib-utils.cpp | 59 +++ common/utils/glib-utils.hpp | 44 +++ packaging/vasum.spec | 3 - server/CMakeLists.txt | 2 +- server/netdev.hpp | 1 + tests/unit_tests/CMakeLists.txt | 2 +- .../unit_tests/socket_test_service/socket-test.cpp | 2 +- zone-daemon/CMakeLists.txt | 10 +- 61 files changed, 4994 insertions(+), 36 deletions(-) create mode 100644 common/config/exception.hpp create mode 100644 common/config/fdstore.cpp create mode 100644 common/config/fdstore.hpp create mode 100644 common/config/fields-union.hpp create mode 100644 common/config/fields.hpp create mode 100644 common/config/from-fdstore-visitor.hpp create mode 100644 common/config/from-gvariant-visitor.hpp create mode 100644 common/config/from-json-visitor.hpp create mode 100644 common/config/from-kvjson-visitor.hpp create mode 100644 common/config/from-kvstore-visitor.hpp create mode 100644 common/config/fs-utils.cpp create mode 100644 common/config/fs-utils.hpp create mode 100644 common/config/is-union.hpp create mode 100644 common/config/is-visitable.hpp create mode 100644 common/config/kvstore.cpp create mode 100644 common/config/kvstore.hpp create mode 100644 common/config/manager.hpp create mode 100644 common/config/sqlite3/connection.cpp create mode 100644 common/config/sqlite3/connection.hpp create mode 100644 common/config/sqlite3/statement.cpp create mode 100644 common/config/sqlite3/statement.hpp create mode 100644 common/config/to-fdstore-visitor.hpp create mode 100644 common/config/to-gvariant-visitor.hpp create mode 100644 common/config/to-json-visitor.hpp create mode 100644 common/config/to-kvstore-visitor.hpp create mode 100644 common/dbus/connection.cpp create mode 100644 common/dbus/connection.hpp create mode 100644 common/dbus/exception.hpp create mode 100644 common/logger/backend-journal.cpp create mode 100644 common/logger/backend-journal.hpp create mode 100644 common/logger/backend-null.hpp create mode 100644 common/logger/backend-stderr.cpp create mode 100644 common/logger/backend-stderr.hpp create mode 100644 common/logger/backend.hpp create mode 100644 common/logger/ccolor.cpp create mode 100644 common/logger/ccolor.hpp create mode 100644 common/logger/formatter.cpp create mode 100644 common/logger/formatter.hpp create mode 100644 common/logger/level.cpp create mode 100644 common/logger/level.hpp create mode 100644 common/logger/logger-scope.cpp create mode 100644 common/logger/logger-scope.hpp create mode 100644 common/logger/logger.cpp create mode 100644 common/logger/logger.hpp create mode 100644 common/utils/glib-utils.cpp create mode 100644 common/utils/glib-utils.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f7aff..6a87b41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ ADD_DEFINITIONS("-pedantic-errors") # Make pedantic warnings into errors ADD_DEFINITIONS(-DPROGRAM_VERSION="${VERSION}") ADD_DEFINITIONS(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}") ADD_DEFINITIONS(-DUSE_EXEC) +ADD_DEFINITIONS(-D__STDC_LIMIT_MACROS) IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Warn about documentation problems diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 0ebbf75..296e638 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -20,22 +20,15 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Client...") FILE(GLOB project_SRCS *.cpp *.hpp *.h) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/callback-guard.hpp - ${COMMON_FOLDER}/utils/callback-guard.cpp - ${COMMON_FOLDER}/utils/glib-loop.cpp - ${COMMON_FOLDER}/utils/glib-loop.hpp - ${COMMON_FOLDER}/base-exception.hpp - ${COMMON_FOLDER}/base-exception.cpp - ${COMMON_FOLDER}/utils/eventfd.hpp - ${COMMON_FOLDER}/utils/eventfd.cpp - ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/fd-utils.cpp - ${COMMON_FOLDER}/epoll/*.hpp - ${COMMON_FOLDER}/epoll/*.cpp - ${COMMON_FOLDER}/ipc/*.hpp - ${COMMON_FOLDER}/ipc/*.cpp - ${COMMON_FOLDER}/ipc/internals/*.hpp - ${COMMON_FOLDER}/ipc/internals/*.cpp) +FILE(GLOB common_SRCS ${COMMON_FOLDER}/config/*.hpp ${COMMON_FOLDER}/config/*.cpp + ${COMMON_FOLDER}/config/sqlite3/*.hpp ${COMMON_FOLDER}/config/sqlite3/*.cpp + ${COMMON_FOLDER}/dbus/*.hpp ${COMMON_FOLDER}/dbus/*.cpp + ${COMMON_FOLDER}/epoll/*.hpp ${COMMON_FOLDER}/epoll/*.cpp + ${COMMON_FOLDER}/ipc/*.hpp ${COMMON_FOLDER}/ipc/*.cpp + ${COMMON_FOLDER}/ipc/internals/*.hpp ${COMMON_FOLDER}/ipc/internals/*.cpp + ${COMMON_FOLDER}/logger/*.hpp ${COMMON_FOLDER}/logger/*.cpp + ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/utils/*.cpp + ${COMMON_FOLDER}/*.hpp ${COMMON_FOLDER}/*.cpp) SET(_LIB_VERSION_ "0.0.1") SET(_LIB_SOVERSION_ "0") @@ -55,7 +48,7 @@ SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY VERSION ${_LIB_VERSION_}) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) -PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger libConfig libsystemd-daemon) +PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libsystemd-daemon libsystemd-journal libcap-ng sqlite3) INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) diff --git a/client/dbus-connection.cpp b/client/dbus-connection.cpp index 7e364d7..b52bd71 100644 --- a/client/dbus-connection.cpp +++ b/client/dbus-connection.cpp @@ -20,7 +20,7 @@ /** * @file * @author Mateusz Malicki (m.malicki2@samsung.com) - * @brief libSimpleDbus's wrapper + * @brief SimpleDbus's wrapper */ #include diff --git a/client/dbus-connection.hpp b/client/dbus-connection.hpp index a760bb6..3cb37ad 100644 --- a/client/dbus-connection.hpp +++ b/client/dbus-connection.hpp @@ -20,7 +20,7 @@ /** * @file * @author Mateusz Malicki (m.malicki2@samsung.com) - * @brief libSimpleDbus's wrapper + * @brief SimpleDbus's wrapper */ #ifndef VASUM_CLIENT_DBUS_CONNECTION_HPP @@ -37,9 +37,9 @@ namespace vasum { namespace client { /** - * libSimpleDbus client definition. + * SimpleDbus client definition. * - * DbusConnection uses libSimpleDbus API. + * DbusConnection uses SimpleDbus API. */ class DbusConnection { public: diff --git a/common/api/method-result-builder.hpp b/common/api/method-result-builder.hpp index 04ede40..89aa7a9 100644 --- a/common/api/method-result-builder.hpp +++ b/common/api/method-result-builder.hpp @@ -47,7 +47,7 @@ public: template void set(const std::shared_ptr& data) { - static_assert(config::isVisitable::value, "Use only libConfig's structures"); + static_assert(config::isVisitable::value, "Use only Config's structures"); setImpl(data); } diff --git a/common/config/exception.hpp b/common/config/exception.hpp new file mode 100644 index 0000000..977ec32 --- /dev/null +++ b/common/config/exception.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Pawelczyk + * + * 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 Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com) + * @brief Exceptions for the configuration + */ + +#ifndef COMMON_CONFIG_EXCEPTION_HPP +#define COMMON_CONFIG_EXCEPTION_HPP + +#include + +namespace config { + +/** + * Base class for exceptions in configuration. + * Error occured during a config file parsing, + * e.g. syntax error + */ +struct ConfigException: public std::runtime_error { + + ConfigException(const std::string& error) : std::runtime_error(error) {} +}; + +} // namespace config + +#endif // COMMON_CONFIG_EXCEPTION_HPP diff --git a/common/config/fdstore.cpp b/common/config/fdstore.cpp new file mode 100644 index 0000000..c1cedfe --- /dev/null +++ b/common/config/fdstore.cpp @@ -0,0 +1,148 @@ +/* + * 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 Definition of a class for writing and reading data from a file descriptor + */ + +#include "config.hpp" + +#include "config/fdstore.hpp" +#include "config/exception.hpp" + +#include +#include +#include +#include +#include + +namespace config { + +namespace { + +void waitForEvent(int fd, + short event, + const std::chrono::high_resolution_clock::time_point deadline) +{ + // Wait for the rest of the data + struct pollfd fds[1]; + fds[0].fd = fd; + fds[0].events = event | POLLHUP; + + for (;;) { + std::chrono::milliseconds timeoutMS = + std::chrono::duration_cast(deadline - std::chrono::high_resolution_clock::now()); + if (timeoutMS.count() < 0) { + throw ConfigException("Timeout"); + } + + int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count()); + + if (ret == -1) { + if (errno == EINTR) { + continue; + } + throw ConfigException("Error in poll: " + std::string(strerror(errno))); + } + + if (ret == 0) { + throw ConfigException("Timeout"); + } + + if (fds[0].revents & POLLHUP) { + throw ConfigException("Peer disconnected"); + } + + // Here Comes the Sun + break; + } +} + +} // namespace + +FDStore::FDStore(int fd) + : mFD(fd) +{ +} + +FDStore::FDStore(const FDStore& store) + : mFD(store.mFD) +{ +} + +FDStore::~FDStore() +{ +} + +void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS) +{ + std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); + + size_t nTotal = 0; + for (;;) { + int n = ::write(mFD, + reinterpret_cast(bufferPtr) + nTotal, + size - nTotal); + if (n >= 0) { + nTotal += n; + if (nTotal == size) { + // All data is written, break loop + break; + } + } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors + } else { + throw ConfigException("Error during writing: " + std::string(strerror(errno))); + } + + waitForEvent(mFD, POLLOUT, deadline); + } +} + +void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeoutMS) +{ + std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); + + size_t nTotal = 0; + for (;;) { + int n = ::read(mFD, + reinterpret_cast(bufferPtr) + nTotal, + size - nTotal); + if (n >= 0) { + nTotal += n; + if (nTotal == size) { + // All data is read, break loop + break; + } + if (n == 0) { + throw ConfigException("Peer disconnected"); + } + } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors + } else { + throw ConfigException("Error during reading: " + std::string(strerror(errno))); + } + + waitForEvent(mFD, POLLIN, deadline); + } +} +} // namespace config diff --git a/common/config/fdstore.hpp b/common/config/fdstore.hpp new file mode 100644 index 0000000..d34ea14 --- /dev/null +++ b/common/config/fdstore.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Declaration of a class for writing and reading data from a file descriptor + */ + +#ifndef COMMON_CONFIG_FDSTORE_HPP +#define COMMON_CONFIG_FDSTORE_HPP + +#include + +namespace config { + +class FDStore { + +public: + /** + * Constructor. One can pass any kind of file descriptor. + * Serialization is NOT written for network purposes, + * rather local communication. + * + * @param fd file descriptor + */ + FDStore(int fd = -1); + FDStore(const FDStore& store); + ~FDStore(); + + /** + * Write data using the file descriptor + * + * @param bufferPtr buffer with the data + * @param size size of the buffer + * @param timeoutMS timeout in milliseconds + */ + void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500); + + /** + * Reads a value of the given type. + * + * @param bufferPtr buffer with the data + * @param size size of the buffer + * @param timeoutMS timeout in milliseconds + */ + void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500); + +private: + int mFD; +}; + +} // namespace config + +#endif // COMMON_CONFIG_FDSTORE_HPP + + diff --git a/common/config/fields-union.hpp b/common/config/fields-union.hpp new file mode 100644 index 0000000..67720e7 --- /dev/null +++ b/common/config/fields-union.hpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki (m.malicki2@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief Macros for declare configuration fields + */ + +#ifndef COMMON_CONFIG_FIELDS_UNION_HPP +#define COMMON_CONFIG_FIELDS_UNION_HPP + +#include "config/fields.hpp" +#include "config/exception.hpp" + +#include +#include + +/** + * Use this macro to declare and register config fields + * + * Example: + * struct Foo { + * std::string bar; + * + * CONFIG_REGISTER + * ( + * bar, + * ) + * }; + * + * struct Config + * { + * CONFIG_DECLARE_UNION + * ( + * Foo, + * int + * ) + * }; + * + * Example of valid configuration: + * 1. { + * "type": "Foo", + * "value": { "bar": "some string" } + * } + * 2. { + * "type": "int", + * "value": 1 + * } + * + * + * Usage: + * Config config; + * // ... + * if (config.isSet()) { + * if (config.is()) { + * Foo& foo = config.as(); + * // ... + * } + * if (config.is())) { + * int field = config.as(); + * // ... + * } + * } else { + * // Config is not set + * Foo foo({"some string"}); + * config.set(foo); + * config.set(std::move(foo)); //< copy sic! + * config.set(Foo({"some string"})); + * } + */ + +class DisbaleMoveAnyWrapper : public boost::any +{ + public: + DisbaleMoveAnyWrapper() {} + DisbaleMoveAnyWrapper(const DisbaleMoveAnyWrapper& any) + : boost::any(static_cast(any)) {}; + DisbaleMoveAnyWrapper& operator=(DisbaleMoveAnyWrapper&& any) = delete; + DisbaleMoveAnyWrapper& operator=(const DisbaleMoveAnyWrapper& any) { + static_cast(*this) = static_cast(any); + return *this; + } +}; + +#define CONFIG_DECLARE_UNION(...) \ +private: \ + DisbaleMoveAnyWrapper mConfigDeclareField; \ + \ + template \ + void visitOption(Visitor& v, const std::string& name) { \ + GENERATE_CODE(GENERATE_UNION_VISIT__, __VA_ARGS__) \ + throw config::ConfigException("Union type error. Unsupported type"); \ + } \ + template \ + void visitOption(Visitor& v, const std::string& name) const { \ + GENERATE_CODE(GENERATE_UNION_VISIT_CONST__, __VA_ARGS__) \ + throw config::ConfigException("Union type error. Unsupported type"); \ + } \ + std::string getOptionName() const { \ + GENERATE_CODE(GENERATE_UNION_NAME__, __VA_ARGS__) \ + return std::string(); \ + } \ + boost::any& getHolder() { \ + return static_cast(mConfigDeclareField); \ + } \ + const boost::any& getHolder() const { \ + return static_cast(mConfigDeclareField); \ + } \ +public: \ + \ + template \ + void accept(Visitor v) { \ + std::string name; \ + v.visit("type", name); \ + visitOption(v, name); \ + } \ + \ + template \ + void accept(Visitor v) const { \ + const std::string name = getOptionName(); \ + if (name.empty()) { \ + throw config::ConfigException("Type is not set"); \ + } \ + v.visit("type", name); \ + visitOption(v, name); \ + } \ + \ + template \ + bool is() const { \ + return boost::any_cast(&getHolder()) != NULL; \ + } \ + template \ + typename std::enable_if::value, Type>::type& as() { \ + if (getHolder().empty()) { \ + throw config::ConfigException("Type is not set"); \ + } \ + return boost::any_cast(getHolder()); \ + } \ + template \ + const Type& as() const { \ + if (getHolder().empty()) { \ + throw config::ConfigException("Type is not set"); \ + } \ + return boost::any_cast(getHolder()); \ + } \ + bool isSet() { \ + return !getOptionName().empty(); \ + } \ + template \ + Type& set(const Type& src) { \ + getHolder() = std::forward(src); \ + if (getOptionName().empty()) { \ + throw config::ConfigException("Unsupported type"); \ + } \ + return as(); \ + } \ + +#define GENERATE_CODE(MACRO, ...) \ + BOOST_PP_LIST_FOR_EACH(MACRO, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) + +#define GENERATE_UNION_VISIT__(r, _, TYPE_) \ + if (#TYPE_ == name) { \ + v.visit("value", set(std::move(TYPE_()))); \ + return; \ + } + +#define GENERATE_UNION_VISIT_CONST__(r, _, TYPE_) \ + if (#TYPE_ == name) { \ + v.visit("value", as()); \ + return; \ + } + +#define GENERATE_UNION_NAME__(r, _, TYPE_) \ + if (is()) { \ + return #TYPE_; \ + } + +#endif // COMMON_CONFIG_FIELDS_UNION_HPP diff --git a/common/config/fields.hpp b/common/config/fields.hpp new file mode 100644 index 0000000..cba5a67 --- /dev/null +++ b/common/config/fields.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Macros for registering configuration fields + */ + +#ifndef COMMON_CONFIG_FIELDS_HPP +#define COMMON_CONFIG_FIELDS_HPP + +#include +#include + +#if BOOST_PP_VARIADICS != 1 +#error variadic macros not supported +#endif + +/** + * Use this macro to register config fields. + * + * Example: + * struct Foo + * { + * std::string bar; + * std::vector tab; + * + * // SubConfigA must also register config fields + * SubConfigA sub_a; + * + * // SubConfigB must also register config fields + * std::vector tab_sub; + * + * CONFIG_REGISTER + * ( + * bar, + * tab, + * sub_a + * ) + * }; + */ + +#define CONFIG_REGISTER_EMPTY \ + template \ + void accept(Visitor ) { \ + } \ + template \ + void accept(Visitor ) const { \ + } \ + +#define CONFIG_REGISTER(...) \ + template \ + void accept(Visitor v) { \ + GENERATE_ELEMENTS__(__VA_ARGS__) \ + } \ + template \ + void accept(Visitor v) const { \ + GENERATE_ELEMENTS__(__VA_ARGS__) \ + } \ + +#define GENERATE_ELEMENTS__(...) \ + BOOST_PP_LIST_FOR_EACH(GENERATE_ELEMENT__, \ + _, \ + BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) \ + +#define GENERATE_ELEMENT__(r, _, element) \ + v.visit(#element, element); \ + +#endif // COMMON_CONFIG_FIELDS_HPP diff --git a/common/config/from-fdstore-visitor.hpp b/common/config/from-fdstore-visitor.hpp new file mode 100644 index 0000000..9b9df42 --- /dev/null +++ b/common/config/from-fdstore-visitor.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak (j.olszak@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Visitor for loading from FDStore + */ + +#ifndef COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP +#define COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/fdstore.hpp" + +#include + +namespace config { + +class FromFDStoreVisitor { +public: + explicit FromFDStoreVisitor(int fd) + : mStore(fd) + { + } + + FromFDStoreVisitor(const FromFDStoreVisitor&) = default; + + FromFDStoreVisitor& operator=(const FromFDStoreVisitor&) = delete; + + template + void visit(const std::string&, T& value) + { + readInternal(value); + } + +private: + FDStore mStore; + + void readInternal(std::string& value) + { + size_t size; + readInternal(size); + value.resize(size); + mStore.read(&value.front(), size); + } + + template::value, int>::type = 0> + void readInternal(T& value) + { + mStore.read(&value, sizeof(T)); + } + + template::value, int>::type = 0> + void readInternal(T& value) + { + FromFDStoreVisitor visitor(*this); + value.accept(visitor); + } + + template + void readInternal(std::vector& values) + { + size_t vectorSize; + readInternal(vectorSize); + values.resize(vectorSize); + + for (T& value : values) { + readInternal(value); + } + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP diff --git a/common/config/from-gvariant-visitor.hpp b/common/config/from-gvariant-visitor.hpp new file mode 100644 index 0000000..040dcae --- /dev/null +++ b/common/config/from-gvariant-visitor.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki (m.malicki2@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief GVariant visitor + */ + +#ifndef COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP +#define COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/exception.hpp" +#include "config/is-union.hpp" + +#include +#include +#include +#include +#include + +namespace config { + +class FromGVariantVisitor { +public: + explicit FromGVariantVisitor(GVariant* variant) + { + //Assume that the visited object is not a union + checkType(variant, G_VARIANT_TYPE_TUPLE); + mIter = g_variant_iter_new(variant); + } + + FromGVariantVisitor(const FromGVariantVisitor& visitor) + : mIter(g_variant_iter_copy(visitor.mIter)) + { + } + + ~FromGVariantVisitor() + { + g_variant_iter_free(mIter); + } + + FromGVariantVisitor& operator=(const FromGVariantVisitor&) = delete; + + template + void visit(const std::string& name, T& value) + { + auto child = makeUnique(g_variant_iter_next_value(mIter)); + if (!child) { + throw config::ConfigException( + "GVariant doesn't match with config. Can't set '" + name + "'"); + } + fromGVariant(child.get(), value); + } + +private: + GVariantIter* mIter; + + static std::unique_ptr makeUnique(GVariant* variant) + { + return std::unique_ptr(variant, g_variant_unref); + } + + static void checkType(GVariant* object, const GVariantType* type) + { + if (!g_variant_is_of_type(object, type)) { + throw ConfigException("Invalid field type"); + } + } + + static void fromGVariant(GVariant* object, std::int32_t& value) + { + checkType(object, G_VARIANT_TYPE_INT32); + value = g_variant_get_int32(object); + } + + static void fromGVariant(GVariant* object, std::int64_t& value) + { + checkType(object, G_VARIANT_TYPE_INT64); + value = g_variant_get_int64(object); + } + + static void fromGVariant(GVariant* object, std::uint32_t& value) + { + checkType(object, G_VARIANT_TYPE_UINT32); + value = g_variant_get_uint32(object); + } + + static void fromGVariant(GVariant* object, std::uint64_t& value) + { + checkType(object, G_VARIANT_TYPE_UINT64); + value = g_variant_get_uint64(object); + } + + static void fromGVariant(GVariant* object, bool& value) + { + checkType(object, G_VARIANT_TYPE_BOOLEAN); + value = g_variant_get_boolean(object); + } + + static void fromGVariant(GVariant* object, double& value) + { + checkType(object, G_VARIANT_TYPE_DOUBLE); + value = g_variant_get_double(object); + } + + static void fromGVariant(GVariant* object, std::string& value) + { + checkType(object, G_VARIANT_TYPE_STRING); + value = g_variant_get_string(object, NULL); + } + + template + static void fromGVariant(GVariant* object, std::vector& value) + { + checkType(object, G_VARIANT_TYPE_ARRAY); + GVariantIter iter; + g_variant_iter_init(&iter, object); + int length = g_variant_iter_n_children(&iter); + value.resize(static_cast(length)); + for (int i = 0; i < length; ++i) { + auto child = makeUnique(g_variant_iter_next_value(&iter)); + assert(child); + fromGVariant(child.get(), value[static_cast(i)]); + } + } + + template + static typename std::enable_if::value>::type + fromGVariant(GVariant* object, T& value) + { + checkType(object, G_VARIANT_TYPE_VARIANT); + auto inner = makeUnique(g_variant_get_variant(object)); + + FromGVariantVisitor visitor(inner.get()); + value.accept(visitor); + } + + template + static typename std::enable_if::value && !isUnion::value>::type + fromGVariant(GVariant* object, T& value) + { + FromGVariantVisitor visitor(object); + value.accept(visitor); + } + +}; + +} // namespace config + +#endif // COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP diff --git a/common/config/from-json-visitor.hpp b/common/config/from-json-visitor.hpp new file mode 100644 index 0000000..2934adf --- /dev/null +++ b/common/config/from-json-visitor.hpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief JSON visitor + */ + +#ifndef COMMON_CONFIG_FROM_JSON_VISITOR_HPP +#define COMMON_CONFIG_FROM_JSON_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/exception.hpp" + +#include +#include +#include + +namespace config { + +class FromJsonVisitor { +public: + explicit FromJsonVisitor(const std::string& jsonString) + : mObject(nullptr) + { + mObject = json_tokener_parse(jsonString.c_str()); + if (mObject == nullptr) { + throw ConfigException("Json parsing error"); + } + } + + FromJsonVisitor(const FromJsonVisitor& visitor) + : mObject(json_object_get(visitor.mObject)) + { + } + + ~FromJsonVisitor() + { + json_object_put(mObject); + } + + FromJsonVisitor& operator=(const FromJsonVisitor&) = delete; + + template + void visit(const std::string& name, T& value) + { + json_object* object = nullptr; + if (!json_object_object_get_ex(mObject, name.c_str(), &object)) { + throw ConfigException("Missing field '" + name + "'"); + } + fromJsonObject(object, value); + } + +private: + json_object* mObject; + + + explicit FromJsonVisitor(json_object* object) + : mObject(json_object_get(object)) + { + } + + static void checkType(json_object* object, json_type type) + { + if (type != json_object_get_type(object)) { + throw ConfigException("Invalid field type"); + } + } + + static void fromJsonObject(json_object* object, std::int32_t& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 > INT32_MAX || value64 < INT32_MIN) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, std::uint32_t& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 > UINT32_MAX || value64 < 0) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, std::int64_t& value) + { + checkType(object, json_type_int); + value = json_object_get_int64(object); + } + + static void fromJsonObject(json_object* object, std::uint64_t& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 < 0) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, bool& value) + { + checkType(object, json_type_boolean); + value = json_object_get_boolean(object); + } + + static void fromJsonObject(json_object* object, double& value) + { + checkType(object, json_type_double); + value = json_object_get_double(object); + } + + static void fromJsonObject(json_object* object, std::string& value) + { + checkType(object, json_type_string); + value = json_object_get_string(object); + } + + template + static void fromJsonObject(json_object* object, std::vector& value) + { + checkType(object, json_type_array); + int length = json_object_array_length(object); + value.resize(static_cast(length)); + for (int i = 0; i < length; ++i) { + fromJsonObject(json_object_array_get_idx(object, i), value[static_cast(i)]); + } + } + + template::value>::type> + static void fromJsonObject(json_object* object, T& value) + { + checkType(object, json_type_object); + FromJsonVisitor visitor(object); + value.accept(visitor); + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_FROM_JSON_VISITOR_HPP diff --git a/common/config/from-kvjson-visitor.hpp b/common/config/from-kvjson-visitor.hpp new file mode 100644 index 0000000..35e1bf7 --- /dev/null +++ b/common/config/from-kvjson-visitor.hpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Krzysztof Dynowski (k.dynowski@samsumg.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Krzysztof Dynowski (k.dynowski@samsumg.com) + * @brief KVStore visitor with defaults values from json + */ + +#ifndef COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP +#define COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP + +#include "config/from-kvstore-visitor.hpp" +#include "config/is-union.hpp" +#include + +namespace config { + +class FromKVJsonVisitor { +public: + FromKVJsonVisitor(KVStore& store, const std::string& json, const std::string& prefix) + : mStore(store) + , mKeyPrefix(prefix) + , mIsUnion(false) + { + mObject = json_tokener_parse(json.c_str()); + if (mObject == nullptr) { + throw ConfigException("Json parsing error"); + } + } + + + ~FromKVJsonVisitor() { + json_object_put(mObject); + } + + FromKVJsonVisitor(const FromKVJsonVisitor& v) : + mStore(v.mStore), + mKeyPrefix(v.mKeyPrefix), + mObject(v.mObject ? json_object_get(v.mObject) : nullptr), + mIsUnion(v.mIsUnion) + { + } + FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete; + + template + void visit(const std::string& name, T& value) { + getValue(name, value); + } + +private: + KVStore& mStore; + std::string mKeyPrefix; + json_object* mObject; + bool mIsUnion; + + // create visitor for field object (visitable object) + FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) : + mStore(v.mStore), + mKeyPrefix(key(v.mKeyPrefix, name)), + mIsUnion(isUnion || v.mIsUnion) + { + json_object* object = nullptr; + if (v.mObject && !json_object_object_get_ex(v.mObject, name.c_str(), &object)) { + if (!mIsUnion) + throw ConfigException("Missing json field " + mKeyPrefix); + } + mObject = object ? json_object_get(object) : nullptr; + } + + // create visitor for vector i-th element (visitable object) + FromKVJsonVisitor(const FromKVJsonVisitor& v, int i, const bool isUnion) : + mStore(v.mStore), + mKeyPrefix(key(v.mKeyPrefix, std::to_string(i))), + mIsUnion(isUnion || v.mIsUnion) + { + json_object* object = nullptr; + if (v.mObject) { + object = json_object_array_get_idx(v.mObject, i); + checkType(object, json_type_object); + } + mObject = object ? json_object_get(object) : nullptr; + } + + template::value, int>::type = 0> + void getValue(const std::string& name, T& t) + { + std::string k = key(mKeyPrefix, name); + if (mStore.exists(k)) { + t = mStore.get(k); + } + else { + json_object* object = nullptr; + if (mObject) { + json_object_object_get_ex(mObject, name.c_str(), &object); + } + if (!object) { + throw ConfigException("Missing json field " + key(mKeyPrefix, name)); + } + fromJsonObject(object, t); + } + } + + template::value, int>::type = 0> + void getValue(const std::string& name, T& t) + { + FromKVJsonVisitor visitor(*this, name, true); + t.accept(visitor); + } + + template::value && !isUnion::value, int>::type = 0> + void getValue(const std::string& name, T& t) + { + FromKVJsonVisitor visitor(*this, name, false); + t.accept(visitor); + } + + int getArraySize(std::string& name, json_object* object) + { + if (mStore.exists(name)) { + return mStore.get(name); + } + if (object) { + return json_object_array_length(object); + } + return -1; + } + + template + void getValue(const std::string& name, std::vector& value) + { + json_object* object = nullptr; + if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) { + checkType(object, json_type_array); + } + + std::string k = key(mKeyPrefix, name); + int length = getArraySize(k, object); + if (length < 0) { + throw ConfigException("Missing array length " + k); + } + value.resize(static_cast(length)); + FromKVJsonVisitor visitor(*this, name, false); + if (mStore.exists(k)) { + json_object_put(visitor.mObject); + visitor.mObject = nullptr; + } + for (int i = 0; i < length; ++i) { + visitor.getValue(i, value[i]); + } + } + + template::value, int>::type = 0> + void getValue(int i, T& t) + { + std::string k = key(mKeyPrefix, std::to_string(i)); + if (mStore.exists(k)) { + t = mStore.get(k); + } + else { + json_object* object = mObject ? json_object_array_get_idx(mObject, i) : nullptr; + if (!object) { + throw ConfigException("Missing json array elem " + k); + } + fromJsonObject(object, t); + } + } + + template::value, int>::type = 0> + void getValue(int i, T& t) + { + FromKVJsonVisitor visitor(*this, i, true); + t.accept(visitor); + } + + template::value && !isUnion::value, int>::type = 0> + void getValue(int i, T& t) + { + FromKVJsonVisitor visitor(*this, i, false); + t.accept(visitor); + } + + template + void getValue(int i, std::vector& value) + { + std::string k = key(mKeyPrefix, std::to_string(i)); + int length = getArraySize(k, mObject); + value.resize(static_cast(length)); + FromKVJsonVisitor visitor(*this, i, false); + if (mStore.exists(k)) { + json_object_put(visitor.mObject); + visitor.mObject = nullptr; + } + for (int i = 0; i < length; ++i) { + visitor.getValue(i, value[i]); + } + } + + static void checkType(json_object* object, json_type type) + { + if (type != json_object_get_type(object)) { + throw ConfigException("Invalid field type " + std::to_string(type)); + } + } + + static void fromJsonObject(json_object* object, int& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 > INT32_MAX || value64 < INT32_MIN) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, std::int64_t& value) + { + checkType(object, json_type_int); + value = json_object_get_int64(object); + } + + static void fromJsonObject(json_object* object, std::uint32_t& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 > UINT32_MAX || value64 < 0) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, std::uint64_t& value) + { + checkType(object, json_type_int); + std::int64_t value64 = json_object_get_int64(object); + if (value64 < 0) { + throw ConfigException("Value out of range"); + } + value = static_cast(value64); + } + + static void fromJsonObject(json_object* object, bool& value) + { + checkType(object, json_type_boolean); + value = json_object_get_boolean(object); + } + + static void fromJsonObject(json_object* object, double& value) + { + checkType(object, json_type_double); + value = json_object_get_double(object); + } + + static void fromJsonObject(json_object* object, std::string& value) + { + checkType(object, json_type_string); + value = json_object_get_string(object); + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP diff --git a/common/config/from-kvstore-visitor.hpp b/common/config/from-kvstore-visitor.hpp new file mode 100644 index 0000000..56bcd14 --- /dev/null +++ b/common/config/from-kvstore-visitor.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak (j.olszak@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Visitor for loading from KVStore + */ + +#ifndef COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP +#define COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/kvstore.hpp" + +namespace config { + +class FromKVStoreVisitor { +public: + FromKVStoreVisitor(KVStore& store, const std::string& prefix) + : mStore(store), + mKeyPrefix(prefix) + { + } + + FromKVStoreVisitor& operator=(const FromKVStoreVisitor&) = delete; + + template + void visit(const std::string& name, T& value) + { + getInternal(key(mKeyPrefix, name), value); + } + +private: + KVStore& mStore; + std::string mKeyPrefix; + + FromKVStoreVisitor(const FromKVStoreVisitor& visitor, const std::string& prefix) + : mStore(visitor.mStore), + mKeyPrefix(prefix) + { + } + + template::value, int>::type = 0> + void getInternal(const std::string& name, T& value) + { + value = mStore.get(name); + } + + template::value, int>::type = 0> + void getInternal(const std::string& name, T& value) + { + FromKVStoreVisitor visitor(*this, name); + value.accept(visitor); + } + + template::value, int>::type = 0> + void getInternal(const std::string& name, std::vector& values) + { + values.clear(); + + size_t vectorSize = mStore.get(name); + if (vectorSize == 0) { + return; + } + + values.resize(vectorSize); + for (size_t i = 0; i < vectorSize; ++i) { + const std::string k = key(name, std::to_string(i)); + getInternal(k, values[i]); + } + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP diff --git a/common/config/fs-utils.cpp b/common/config/fs-utils.cpp new file mode 100644 index 0000000..1b08dce --- /dev/null +++ b/common/config/fs-utils.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Filesystem helper functions + */ + +#include "config/fs-utils.hpp" + +#include +#include + + +namespace config { +namespace fsutils { + +bool readFileContent(const std::string& path, std::string& result) +{ + std::ifstream file(path); + + if (!file) { + return false; + } + + file.seekg(0, std::ios::end); + std::streampos length = file.tellg(); + if (length < 0) { + return false; + } + result.resize(static_cast(length)); + file.seekg(0, std::ios::beg); + + file.read(&result[0], length); + if (!file) { + result.clear(); + return false; + } + + return true; +} + +bool saveFileContent(const std::string& path, const std::string& content) +{ + std::ofstream file(path); + if (!file) { + return false; + } + file.write(content.data(), static_cast(content.size())); + if (!file) { + return false; + } + return true; +} + +} // namespace fsutils +} // namespace config diff --git a/common/config/fs-utils.hpp b/common/config/fs-utils.hpp new file mode 100644 index 0000000..a9dccec --- /dev/null +++ b/common/config/fs-utils.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief src/config/manager.hpp + */ + +#ifndef COMMON_CONFIG_FS_UTILS_HPP +#define COMMON_CONFIG_FS_UTILS_HPP + +#include + +namespace config { +namespace fsutils { + +bool readFileContent(const std::string& path, std::string& result); +bool saveFileContent(const std::string& path, const std::string& content); + +inline std::string readFileContent(const std::string& path) { + std::string content; + return readFileContent(path, content) ? content : std::string(); +} +} // namespace fsutils +} // namespace config + +#endif // COMMON_CONFIG_FS_UTILS_HPP diff --git a/common/config/is-union.hpp b/common/config/is-union.hpp new file mode 100644 index 0000000..63636ec --- /dev/null +++ b/common/config/is-union.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Krzysztof Dynowski (k.dynowski@samsumg.com) + * @brief Internal configuration helper + */ + +#ifndef COMMON_CONFIG_IS_UNION_HPP +#define COMMON_CONFIG_IS_UNION_HPP + +#include "config/is-visitable.hpp" + +namespace config { + +// generic member checker, start +template +struct has_member_impl { + template + static std::true_type check(typename F::template checker__* =0); + + template + static std::false_type check(...); + + static const bool value = std::is_same(0)), std::true_type>::value; +}; + +template +struct has_member : public std::integral_constant::value> {}; +// generic member checker, end + + +template +struct check_union : isVisitable { + template + struct checker__ {}; +}; +template +struct isUnion : has_member> {}; + +//Note: +// unfortunately, above generic has_member can't be used for isVisitable +// because Vistable need 'accept' OR 'accept const', while has_member make exect match +// e.g accept AND accept const + +} // namespace config + +#endif // COMMON_CONFIG_IS_UNION_HPP + diff --git a/common/config/is-visitable.hpp b/common/config/is-visitable.hpp new file mode 100644 index 0000000..d63069f --- /dev/null +++ b/common/config/is-visitable.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Internal configuration helper + */ + +#ifndef COMMON_CONFIG_IS_VISITABLE_HPP +#define COMMON_CONFIG_IS_VISITABLE_HPP + +#include + +namespace config { + +template +struct isVisitableHelper__ { + struct Visitor {}; + + template static std::true_type + test(decltype(std::declval().template accept(Visitor()))*); + + template static std::false_type + test(...); + + static constexpr bool value = std::is_same(0)), std::true_type>::value; +}; + +/** + * Helper for compile-time checking against existance of template method 'accept'. + */ +template +struct isVisitable : public std::integral_constant::value> {}; + +} // namespace config + +#endif // COMMON_CONFIG_IS_VISITABLE_HPP diff --git a/common/config/kvstore.cpp b/common/config/kvstore.cpp new file mode 100644 index 0000000..49656ae --- /dev/null +++ b/common/config/kvstore.cpp @@ -0,0 +1,342 @@ +/* + * 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 Definition of a class for key-value storage in a sqlite3 database + */ + +#include "config.hpp" + +#include "config/kvstore.hpp" +#include "config/exception.hpp" + +#include +#include +#include +#include +#include + +namespace config { + +namespace { + +const int AUTO_DETERM_SIZE = -1; +const int FIRST_COLUMN = 0; + +struct ScopedReset { + ScopedReset(std::unique_ptr& stmtPtr) + : mStmtPtr(stmtPtr) {} + ~ScopedReset() + { + mStmtPtr->reset(); + } +private: + std::unique_ptr& mStmtPtr; +}; + +/** + * Escape characters used by the GLOB function. + */ +void sqliteEscapeStr(::sqlite3_context* context, int argc, ::sqlite3_value** values) +{ + char* inBuff = (char*)sqlite3_value_text(values[0]); + if (argc != 1 || inBuff == NULL) { + sqlite3_result_error(context, "SQL function escapeSequence() called with invalid arguments.\n", -1); + return; + } + + std::string in(inBuff); + static const std::set toEscape({'?', '*', '[', ']'}); + + // Compute the out size + auto isEscapeChar = [&](char c) { + return toEscape.count(c) == 1; + }; + size_t numEscape = std::count_if(in.begin(), + in.end(), + isEscapeChar); + if (numEscape == 0) { + sqlite3_result_text(context, in.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); + } + + // Escape characters + std::string out(in.size() + 2 * numEscape, 'x'); + for (size_t i = 0, j = 0; + i < in.size(); + ++i, ++j) { + if (isEscapeChar(in[i])) { + out[j] = '['; + ++j; + out[j] = in[i]; + ++j; + out[j] = ']'; + } else { + out[j] = in[i]; + } + } + sqlite3_result_text(context, out.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); +} + +} // namespace + +KVStore::Transaction::Transaction(KVStore& kvStore) + : mLock(kvStore.mMutex) + , mKVStore(kvStore) + , mIsOuter(kvStore.mTransactionDepth == 0) +{ + if (mKVStore.mIsTransactionCommited) { + throw ConfigException("Previous transaction is not closed"); + } + if (mIsOuter) { + mKVStore.mConn.exec("BEGIN EXCLUSIVE TRANSACTION"); + } + ++mKVStore.mTransactionDepth; +} + +KVStore::Transaction::~Transaction() +{ + --mKVStore.mTransactionDepth; + if (mIsOuter) { + if (mKVStore.mIsTransactionCommited) { + mKVStore.mIsTransactionCommited = false; + } else { + mKVStore.mConn.exec("ROLLBACK TRANSACTION"); + } + } +} + +void KVStore::Transaction::commit() +{ + if (mKVStore.mIsTransactionCommited) { + throw ConfigException("Transaction already commited"); + } + if (mIsOuter) { + mKVStore.mConn.exec("COMMIT TRANSACTION"); + mKVStore.mIsTransactionCommited = true; + } +} + +KVStore::KVStore(const std::string& path) + : mTransactionDepth(0), + mIsTransactionCommited(false), + mPath(path), + mConn(path) +{ + setupDb(); + createFunctions(); + prepareStatements(); +} + +KVStore::~KVStore() +{ + assert(mTransactionDepth == 0); +} + +void KVStore::setupDb() +{ + // called only from ctor, transaction is not needed + mConn.exec("CREATE TABLE IF NOT EXISTS data (key TEXT PRIMARY KEY, value TEXT NOT NULL)"); +} + +void KVStore::prepareStatements() +{ + mGetValueStmt.reset( + new sqlite3::Statement(mConn, "SELECT value FROM data WHERE key = ? LIMIT 1")); + mGetKeyExistsStmt.reset( + // following line left in comment to have example of any subkey matching + //new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 OR key GLOB escapeStr(?1) || '.*' LIMIT 1")); + new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 LIMIT 1")); + mGetIsEmptyStmt.reset( + new sqlite3::Statement(mConn, "SELECT 1 FROM data LIMIT 1")); + mSetValueStmt.reset( + new sqlite3::Statement(mConn, "INSERT OR REPLACE INTO data (key, value) VALUES (?,?)")); + mRemoveValuesStmt.reset( + new sqlite3::Statement(mConn, "DELETE FROM data WHERE key = ?1 OR key GLOB escapeStr(?1) ||'.*' ")); + mGetKeysStmt.reset( + new sqlite3::Statement(mConn, "SELECT key FROM data")); +} + +void KVStore::createFunctions() +{ + int ret = sqlite3_create_function(mConn.get(), "escapeStr", 1, SQLITE_ANY, 0, &sqliteEscapeStr, 0, 0); + if (ret != SQLITE_OK) { + throw ConfigException("Error during creating functions: " + mConn.getErrorMessage()); + } +} + +void KVStore::clear() +{ + Transaction transaction(*this); + mConn.exec("DELETE FROM data"); + transaction.commit(); +} + +bool KVStore::isEmpty() +{ + Transaction transaction(*this); + ScopedReset scopedReset(mGetIsEmptyStmt); + + int ret = ::sqlite3_step(mGetIsEmptyStmt->get()); + if (ret != SQLITE_DONE && ret != SQLITE_ROW) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + + transaction.commit(); + return ret == SQLITE_DONE; +} + +bool KVStore::exists(const std::string& key) +{ + Transaction transaction(*this); + ScopedReset scopedReset(mGetKeyExistsStmt); + + ::sqlite3_bind_text(mGetKeyExistsStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); + + int ret = ::sqlite3_step(mGetKeyExistsStmt->get()); + if (ret != SQLITE_DONE && ret != SQLITE_ROW) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + + transaction.commit(); + return ret == SQLITE_ROW; +} + +void KVStore::remove(const std::string& key) +{ + Transaction transaction(*this); + ScopedReset scopedReset(mRemoveValuesStmt); + + ::sqlite3_bind_text(mRemoveValuesStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC); + + if (::sqlite3_step(mRemoveValuesStmt->get()) != SQLITE_DONE) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + transaction.commit(); +} + +void KVStore::setInternal(const std::string& key, const std::string& value) +{ + Transaction transaction(*this); + ScopedReset scopedReset(mSetValueStmt); + + ::sqlite3_bind_text(mSetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC); + ::sqlite3_bind_text(mSetValueStmt->get(), 2, value.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC); + + + if (::sqlite3_step(mSetValueStmt->get()) != SQLITE_DONE) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + transaction.commit(); +} + +void KVStore::setInternal(const std::string& key, const std::initializer_list& values) +{ + setInternal(key, std::vector(values)); +} + +void KVStore::setInternal(const std::string& key, const std::vector& values) +{ + if (values.size() > std::numeric_limits::max()) { + throw ConfigException("Too many values to insert"); + } + + Transaction transaction(*this); + + remove(key); + + // Save vector's capacity + setInternal(key, values.size()); + + // Save vector's elements + for (unsigned int i = 0; i < values.size(); ++i) { + setInternal(config::key(key, std::to_string(i)), + values[i]); + } + transaction.commit(); +} + +std::string KVStore::getInternal(const std::string& key, std::string*) +{ + Transaction transaction(*this); + ScopedReset scopedReset(mGetValueStmt); + + ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); + + int ret = ::sqlite3_step(mGetValueStmt->get()); + if (ret == SQLITE_DONE) { + throw ConfigException("No value corresponding to the key: " + key + "@" + mPath); + } + if (ret != SQLITE_ROW) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + + std::string value = reinterpret_cast( + sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN)); + + transaction.commit(); + return value; +} + +std::vector KVStore::getInternal(const std::string& key, std::vector*) +{ + Transaction transaction(*this); + + unsigned int valuesSize = get(key); + std::vector values(valuesSize); + if (valuesSize == 0) { + transaction.commit(); + return values; + } + + for (unsigned int i = 0; i < values.size(); ++i) { + values[i] = getInternal(config::key(key, std::to_string(i)), + static_cast(nullptr)); + + } + + transaction.commit(); + return values; +} + +std::vector KVStore::getKeys() +{ + Transaction transaction(*this); + ScopedReset scopedReset(mGetKeysStmt); + + std::vector result; + + for (;;) { + int ret = ::sqlite3_step(mGetKeysStmt->get()); + if (ret == SQLITE_DONE) { + break; + } + if (ret != SQLITE_ROW) { + throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); + } + const char* key = reinterpret_cast(sqlite3_column_text(mGetKeysStmt->get(), + FIRST_COLUMN)); + result.push_back(key); + } + + transaction.commit(); + return result; +} + +} // namespace config diff --git a/common/config/kvstore.hpp b/common/config/kvstore.hpp new file mode 100644 index 0000000..0717665 --- /dev/null +++ b/common/config/kvstore.hpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Declaration of a class for key-value storage in a sqlite3 database + */ + +#ifndef COMMON_CONFIG_KVSTORE_HPP +#define COMMON_CONFIG_KVSTORE_HPP + +#include "config/sqlite3/connection.hpp" +#include "config/sqlite3/statement.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace config { + +class KVStore { + +public: + /** + * A guard struct for thread synchronization and transaction management. + */ + class Transaction { + public: + Transaction(KVStore& store); + ~Transaction(); + + Transaction(const Transaction&) = delete; + Transaction& operator=(const Transaction&) = delete; + + void commit(); + private: + std::unique_lock mLock; + KVStore& mKVStore; + bool mIsOuter; + }; + + /** + * @param path configuration database file path + */ + explicit KVStore(const std::string& path); + ~KVStore(); + + KVStore(const KVStore&) = delete; + KVStore& operator=(const KVStore&) = delete; + + /** + * Clears all the stored data + */ + void clear(); + + /** + * @return Is there any data stored + */ + bool isEmpty(); + + /** + * @param key string regexp of the stored values + * + * @return Does this key exist in the database + */ + bool exists(const std::string& key); + + /** + * Removes values corresponding to the passed key. + * Many values may correspond to one key, so many values may + * need to be deleted + * + * @param key string regexp of the stored values + */ + void remove(const std::string& key); + + /** + * Stores a single value corresponding to the passed key + * + * @param key string key of the value + * @param value value corresponding to the key + */ + template + void set(const std::string& key, const T& value) + { + return setInternal(key, value); + } + + /** + * Gets the value corresponding to the key. + * Uses stringstreams to parse. + * + * @param key string key of the value + * @tparam T = std::string desired type of the return value + * @return value corresponding to the key + */ + template + T get(const std::string& key) + { + return getInternal(key, static_cast(nullptr)); + } + + /** + * Returns all stored keys. + */ + std::vector getKeys(); + +private: + typedef std::lock_guard Lock; + + std::recursive_mutex mMutex; + size_t mTransactionDepth; + bool mIsTransactionCommited; + + void setInternal(const std::string& key, const std::string& value); + void setInternal(const std::string& key, const std::initializer_list& values); + void setInternal(const std::string& key, const std::vector& values); + template + void setInternal(const std::string& key, const T& value); + template + void setInternal(const std::string& key, const std::vector& values); + + std::string getInternal(const std::string& key, std::string*); + std::vector getInternal(const std::string& key, std::vector*); + template + T getInternal(const std::string& key, T*); + template + std::vector getInternal(const std::string& key, std::vector*); + + std::string mPath; + sqlite3::Connection mConn; + std::unique_ptr mGetValueStmt; + std::unique_ptr mGetKeyExistsStmt; + std::unique_ptr mGetIsEmptyStmt; + std::unique_ptr mGetValueListStmt; + std::unique_ptr mSetValueStmt; + std::unique_ptr mRemoveValuesStmt; + std::unique_ptr mGetKeysStmt; + + void setupDb(); + void prepareStatements(); + void createFunctions(); +}; + +namespace { +template +std::string toString(const T& value) +{ + std::ostringstream oss; + oss << value; + return oss.str(); +} + +template +T fromString(const std::string& strValue) +{ + std::istringstream iss(strValue); + T value; + iss >> value; + return value; +} + +} // namespace + +template +void KVStore::setInternal(const std::string& key, const T& value) +{ + setInternal(key, toString(value)); +} + +template +void KVStore::setInternal(const std::string& key, const std::vector& values) +{ + std::vector strValues(values.size()); + + std::transform(values.begin(), + values.end(), + strValues.begin(), + toString); + + setInternal(key, strValues); +} + +template +T KVStore::getInternal(const std::string& key, T*) +{ + return fromString(getInternal(key, static_cast(nullptr))); +} + +template +std::vector KVStore::getInternal(const std::string& key, std::vector*) +{ + std::vector strValues = getInternal(key, static_cast*>(nullptr)); + std::vector values(strValues.size()); + + std::transform(strValues.begin(), + strValues.end(), + values.begin(), + fromString); + + return values; +} + +/** + * Concatenates all parameters into one std::string. + * Uses '.' to connect the terms. + * @param args components of the string + * @tparam delim optional delimiter + * @tparam typename ... Args any type implementing str + * @return string created from he args + */ +template +std::string key(const Arg1& a1, const Args& ... args) +{ + std::string ret = toString(a1); + std::initializer_list strings {toString(args)...}; + for (const std::string& s : strings) { + ret += delim + s; + } + + return ret; +} + +/** + * Function added for key function completeness. + * + * @tparam delim = '.' parameter not used, added for consistency + * @return empty string + */ +template +std::string key() +{ + return std::string(); +} + +} // namespace config + +#endif // COMMON_CONFIG_KVSTORE_HPP + + diff --git a/common/config/manager.hpp b/common/config/manager.hpp new file mode 100644 index 0000000..0deb8d8 --- /dev/null +++ b/common/config/manager.hpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Configuration management functions + */ + +#ifndef COMMON_CONFIG_MANAGER_HPP +#define COMMON_CONFIG_MANAGER_HPP + +#include "config/to-gvariant-visitor.hpp" +#include "config/to-json-visitor.hpp" +#include "config/to-kvstore-visitor.hpp" +#include "config/to-fdstore-visitor.hpp" +#include "config/from-gvariant-visitor.hpp" +#include "config/from-json-visitor.hpp" +#include "config/from-kvstore-visitor.hpp" +#include "config/from-fdstore-visitor.hpp" +#include "config/from-kvjson-visitor.hpp" +#include "config/fs-utils.hpp" +#include "config/is-union.hpp" + +namespace config { + +/** + * Fills the configuration with data stored in the GVariant + * + * @param gvariant configuration in GVariant type + * @param config visitable structure to fill + */ +template +void loadFromGVariant(GVariant* gvariant, Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + static_assert(!isUnion::value, "Don't use CONFIG_DECLARE_UNION in top level config"); + + FromGVariantVisitor visitor(gvariant); + config.accept(visitor); +} + +/** + * Saves the config in a GVariant + * + * @param config visitable structure to convert + */ +template +GVariant* saveToGVariant(const Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + static_assert(!isUnion::value, "Don't use CONFIG_DECLARE_UNION in top level config"); + + ToGVariantVisitor visitor; + config.accept(visitor); + return visitor.toVariant(); +} + +/** + * Fills the configuration with data stored in the json string + * + * @param jsonString configuration in a json format + * @param config visitable structure to fill + */ +template +void loadFromJsonString(const std::string& jsonString, Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + FromJsonVisitor visitor(jsonString); + config.accept(visitor); +} + +/** + * Creates a string representation of the configuration in json format + * + * @param config visitable structure to convert + */ +template +std::string saveToJsonString(const Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + ToJsonVisitor visitor; + config.accept(visitor); + return visitor.toString(); +} + +/** + * Loads the config from a json file + * + * @param filename path to the file + * @param config visitable structure to load + */ +template +void loadFromJsonFile(const std::string& filename, Config& config) +{ + std::string content; + if (!fsutils::readFileContent(filename, content)) { + throw ConfigException("Could not load " + filename); + } + try { + loadFromJsonString(content, config); + } catch (ConfigException& e) { + throw ConfigException("Error in " + filename + ": " + e.what()); + } +} + +/** + * Saves the config in a json file + * + * @param filename path to the file + * @param config visitable structure to save + */ +template +void saveToJsonFile(const std::string& filename, const Config& config) +{ + const std::string content = saveToJsonString(config); + if (!fsutils::saveFileContent(filename, content)) { + throw ConfigException("Could not save " + filename); + } +} + +/** + * Loads a visitable configuration from KVStore. + * + * @param filename path to the KVStore db + * @param config visitable structure to load + * @param configName name of the configuration inside the KVStore db + */ +template +void loadFromKVStore(const std::string& filename, Config& config, const std::string& configName) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + KVStore store(filename); + KVStore::Transaction transaction(store); + FromKVStoreVisitor visitor(store, configName); + config.accept(visitor); + transaction.commit(); +} + +/** + * Saves the config to a KVStore. + * + * @param filename path to the KVStore db + * @param config visitable structure to save + * @param configName name of the config inside the KVStore db + */ +template +void saveToKVStore(const std::string& filename, const Config& config, const std::string& configName) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + KVStore store(filename); + KVStore::Transaction transaction(store); + ToKVStoreVisitor visitor(store, configName); + config.accept(visitor); + transaction.commit(); +} + +/** + * Load the config from KVStore with defaults given in json + * + * @param kvfile path to the KVStore db + * @param jsonfile path to json file with defaults + * @param config visitable structure to save + * @param kvConfigName name of the config inside the KVStore db + */ +template +void loadFromKVStoreWithJson(const std::string& kvfile, + const std::string& json, + Config& config, + const std::string& kvConfigName) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + KVStore store(kvfile); + KVStore::Transaction transaction(store); + FromKVJsonVisitor visitor(store, json, kvConfigName); + config.accept(visitor); + transaction.commit(); +} + +/** + * Load the config from KVStore with defaults given in json file + * + * @param kvfile path to the KVStore db + * @param jsonfile path to json file with defaults + * @param config visitable structure to save + * @param kvConfigName name of the config inside the KVStore db + */ +template +void loadFromKVStoreWithJsonFile(const std::string& kvfile, + const std::string& jsonfile, + Config& config, + const std::string& kvConfigName) +{ + std::string content; + if (!fsutils::readFileContent(jsonfile, content)) { + throw ConfigException("Could not load " + jsonfile); + } + try { + loadFromKVStoreWithJson(kvfile, content, config, kvConfigName); + } catch (ConfigException& e) { + throw ConfigException("Error in " + jsonfile + ": " + e.what()); + } +} + +/** + * Load binary data from a file/socket/pipe represented by the fd + * + * @param fd file descriptor + * @param config visitable structure to load + */ +template +void loadFromFD(const int fd, Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + FromFDStoreVisitor visitor(fd); + config.accept(visitor); +} + +/** + * Save binary data to a file/socket/pipe represented by the fd + * + * @param fd file descriptor + * @param config visitable structure to save + */ +template +void saveToFD(const int fd, const Config& config) +{ + static_assert(isVisitable::value, "Use CONFIG_REGISTER macro"); + + ToFDStoreVisitor visitor(fd); + config.accept(visitor); +} + +} // namespace config + +#endif // COMMON_CONFIG_MANAGER_HPP diff --git a/common/config/sqlite3/connection.cpp b/common/config/sqlite3/connection.cpp new file mode 100644 index 0000000..cb25694 --- /dev/null +++ b/common/config/sqlite3/connection.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Definition of the class managing a sqlite3 database connection + */ + + +#include "config/sqlite3/connection.hpp" +#include "config/exception.hpp" + +namespace config { +namespace sqlite3 { + +Connection::Connection(const std::string& path) +{ + if (path.empty()) { + // Sqlite creates temporary database in case of empty path + // but we want to forbid this. + throw ConfigException("Error opening the database: empty path"); + } + if (::sqlite3_open_v2(path.c_str(), + &mDbPtr, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, + NULL) != SQLITE_OK) { + throw ConfigException("Error opening the database: " + getErrorMessage()); + } + + if (mDbPtr == NULL) { + throw ConfigException("Error opening the database: Unable to allocate memory."); + } +} + +Connection::~Connection() +{ + if (::sqlite3_close(mDbPtr) != SQLITE_OK) { + throw ConfigException("Error during closing the database. Error: " + getErrorMessage()); + } +} + +void Connection::exec(const std::string& query) +{ + char* mess; + if (::sqlite3_exec(mDbPtr, query.c_str(), 0, 0, &mess) != SQLITE_OK) { + throw ConfigException("Error during executing statement " + std::string(mess)); + } +} + +::sqlite3* Connection::get() +{ + return mDbPtr; +} + +std::string Connection::getErrorMessage() +{ + return std::string(sqlite3_errmsg(mDbPtr)); +} + +} // namespace sqlite3 +} // namespace config diff --git a/common/config/sqlite3/connection.hpp b/common/config/sqlite3/connection.hpp new file mode 100644 index 0000000..850332a --- /dev/null +++ b/common/config/sqlite3/connection.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Declaration of the class managing a sqlite3 database connection + */ + +#ifndef COMMON_CONFIG_SQLITE3_CONNECTION_HPP +#define COMMON_CONFIG_SQLITE3_CONNECTION_HPP + +#include +#include + +namespace config { +namespace sqlite3 { + +struct Connection { + /** + * @param path database file path + */ + Connection(const std::string& path); + Connection(const Connection&) = delete; + ~Connection(); + + /** + * @return pointer to the corresponding sqlite3 database object + */ + ::sqlite3* get(); + + /** + * @return last error message in the database + */ + std::string getErrorMessage(); + + /** + * Executes the query in the database. + * + * @param query query to be executed + */ + void exec(const std::string& query); + +private: + ::sqlite3* mDbPtr; +}; + +} // namespace sqlite3 +} // namespace config + +#endif // COMMON_CONFIG_SQLITE3_CONNECTION_HPP diff --git a/common/config/sqlite3/statement.cpp b/common/config/sqlite3/statement.cpp new file mode 100644 index 0000000..287cb1c --- /dev/null +++ b/common/config/sqlite3/statement.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Definition of the class managing a sqlite3 statement + */ + +#include "config/sqlite3/statement.hpp" +#include "config/exception.hpp" + + +namespace config { +namespace sqlite3 { + +Statement::Statement(sqlite3::Connection& connRef, const std::string& query) + : mConnRef(connRef) +{ + if (::sqlite3_prepare_v2(connRef.get(), + query.c_str(), + query.size(), + &mStmtPtr, + NULL) + != SQLITE_OK) { + throw ConfigException("Error during preparing statement " + + mConnRef.getErrorMessage()); + } + + if (mStmtPtr == NULL) { + throw ConfigException("Wrong query: " + query); + } +} + +Statement::Statement::~Statement() +{ + if (::sqlite3_finalize(mStmtPtr) != SQLITE_OK) { + throw ConfigException("Error during finalizing statement " + + mConnRef.getErrorMessage()); + } +} + +sqlite3_stmt* Statement::get() +{ + return mStmtPtr; +} + +void Statement::reset() +{ + if (::sqlite3_clear_bindings(mStmtPtr) != SQLITE_OK) { + throw ConfigException("Error unbinding statement: " + + mConnRef.getErrorMessage()); + } + + if (::sqlite3_reset(mStmtPtr) != SQLITE_OK) { + throw ConfigException("Error reseting statement: " + + mConnRef.getErrorMessage()); + } +} + +} // namespace sqlite3 +} // namespace config diff --git a/common/config/sqlite3/statement.hpp b/common/config/sqlite3/statement.hpp new file mode 100644 index 0000000..48a1fca --- /dev/null +++ b/common/config/sqlite3/statement.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Declaration of the class managing a sqlite3 statement + */ + +#ifndef COMMON_CONFIG_SQLITE3_STATEMENT_HPP +#define COMMON_CONFIG_SQLITE3_STATEMENT_HPP + +#include "config/sqlite3/connection.hpp" + +#include +#include + +namespace config { +namespace sqlite3 { + +struct Statement { + + /** + * @param connRef reference to the Connection object + * @param query query to be executed + */ + Statement(sqlite3::Connection& connRef, const std::string& query); + ~Statement(); + + /** + * @return pointer to the sqlite3 statement + */ + sqlite3_stmt* get(); + + /** + * Clears the bindings and resets the statement. + * After this the statement can be executed again + */ + void reset(); + +private: + ::sqlite3_stmt* mStmtPtr; + sqlite3::Connection& mConnRef; +}; + +} // namespace sqlite3 +} // namespace config + +#endif // COMMON_CONFIG_SQLITE3_STATEMENT_HPP + + diff --git a/common/config/to-fdstore-visitor.hpp b/common/config/to-fdstore-visitor.hpp new file mode 100644 index 0000000..50756c1 --- /dev/null +++ b/common/config/to-fdstore-visitor.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak (j.olszak@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Visitor for saving to FDStore + */ + +#ifndef COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP +#define COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/fdstore.hpp" + +#include + +namespace config { + +class ToFDStoreVisitor { + +public: + ToFDStoreVisitor(int fd) + : mStore(fd) + { + } + + ToFDStoreVisitor(const ToFDStoreVisitor&) = default; + + ToFDStoreVisitor& operator=(const ToFDStoreVisitor&) = delete; + + template + void visit(const std::string&, const T& value) + { + writeInternal(value); + } + +private: + FDStore mStore; + + void writeInternal(const std::string& value) + { + writeInternal(value.size()); + mStore.write(value.c_str(), value.size()); + } + + template::value, int>::type = 0> + void writeInternal(const T& value) + { + mStore.write(&value, sizeof(T)); + } + + template::value, int>::type = 0> + void writeInternal(const T& value) + { + ToFDStoreVisitor visitor(*this); + value.accept(visitor); + } + + template + void writeInternal(const std::vector& values) + { + writeInternal(values.size()); + for (const T& value : values) { + writeInternal(value); + } + } + +}; + +} // namespace config + +#endif // COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP diff --git a/common/config/to-gvariant-visitor.hpp b/common/config/to-gvariant-visitor.hpp new file mode 100644 index 0000000..bb94e49 --- /dev/null +++ b/common/config/to-gvariant-visitor.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Mateusz Malicki (m.malicki2@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Mateusz Malicki (m.malicki2@samsung.com) + * @brief GVariant visitor + */ + +#ifndef COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP +#define COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/is-union.hpp" + +#include +#include +#include + +namespace config { + +class ToGVariantVisitor { + +public: + ToGVariantVisitor() + : mBuilder(g_variant_builder_new(G_VARIANT_TYPE_TUPLE)) + { + } + + ToGVariantVisitor(const ToGVariantVisitor& visitor) + : mBuilder(visitor.mBuilder ? g_variant_builder_ref(visitor.mBuilder) : nullptr) + { + } + + ~ToGVariantVisitor() + { + if (mBuilder) { + g_variant_builder_unref(mBuilder); + } + } + + ToGVariantVisitor& operator=(const ToGVariantVisitor&) = delete; + + GVariant* toVariant() + { + if (mBuilder) { + GVariant* ret = g_variant_builder_end(mBuilder); + g_variant_builder_unref(mBuilder); + mBuilder = nullptr; + return ret; + } + return nullptr; + } + + template + void visit(const std::string& /* name */, const T& value) + { + writeInternal(value); + } +private: + GVariantBuilder* mBuilder; + + void writeInternal(std::int32_t value) { add("i", value); }; + void writeInternal(std::int64_t value) { add("x", value); }; + void writeInternal(std::uint32_t value) { add("u", value); }; + void writeInternal(std::uint64_t value) { add("t", value); }; + void writeInternal(bool value) { add("b", value); }; + void writeInternal(double value) { add("d", value); }; + void writeInternal(const std::string& value) { add("s", value.c_str()); }; + + template + void writeInternal(const std::vector& value) + { + if (!value.empty()) { + g_variant_builder_open(mBuilder, G_VARIANT_TYPE_ARRAY); + for (const T& v : value) { + writeInternal(v); + } + g_variant_builder_close(mBuilder); + } else { + g_variant_builder_add(mBuilder, "as", NULL); + } + } + + template + typename std::enable_if::value && !isUnion::value>::type + writeInternal(const T& value) + { + ToGVariantVisitor visitor; + value.accept(visitor); + g_variant_builder_add_value(mBuilder, visitor.toVariant()); + } + + template + typename std::enable_if::value && isUnion::value>::type + writeInternal(const T& value) + { + ToGVariantVisitor visitor; + value.accept(visitor); + add("v", visitor.toVariant()); + } + + template + void add(const char* type, Value value) { + g_variant_builder_add(mBuilder, type, value); + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP diff --git a/common/config/to-json-visitor.hpp b/common/config/to-json-visitor.hpp new file mode 100644 index 0000000..f524900 --- /dev/null +++ b/common/config/to-json-visitor.hpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief JSON visitor + */ + +#ifndef COMMON_CONFIG_TO_JSON_VISITOR_HPP +#define COMMON_CONFIG_TO_JSON_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/exception.hpp" + +#include +#include +#include + +namespace config { + +class ToJsonVisitor { + +public: + ToJsonVisitor() + : mObject(json_object_new_object()) + { + } + + ToJsonVisitor(const ToJsonVisitor& visitor) + : mObject(json_object_get(visitor.mObject)) + { + } + + ~ToJsonVisitor() + { + json_object_put(mObject); + } + + ToJsonVisitor& operator=(const ToJsonVisitor&) = delete; + + std::string toString() const + { + return json_object_to_json_string(mObject); + } + + template + void visit(const std::string& name, const T& value) + { + json_object_object_add(mObject, name.c_str(), toJsonObject(value)); + } +private: + json_object* mObject; + + + json_object* detach() + { + json_object* ret = mObject; + mObject = nullptr; + return ret; + } + + static json_object* toJsonObject(std::int32_t value) + { + return json_object_new_int(value); + } + + static json_object* toJsonObject(std::int64_t value) + { + return json_object_new_int64(value); + } + + static json_object* toJsonObject(std::uint32_t value) + { + if (value > INT32_MAX) { + throw ConfigException("Value out of range"); + } + return json_object_new_int(value); + } + + static json_object* toJsonObject(std::uint64_t value) + { + if (value > INT64_MAX) { + throw ConfigException("Value out of range"); + } + return json_object_new_int64(value); + } + + static json_object* toJsonObject(bool value) + { + return json_object_new_boolean(value); + } + + static json_object* toJsonObject(double value) + { + return json_object_new_double(value); + } + + static json_object* toJsonObject(const std::string& value) + { + return json_object_new_string(value.c_str()); + } + + template + static json_object* toJsonObject(const std::vector& value) + { + json_object* array = json_object_new_array(); + for (const T& v : value) { + json_object_array_add(array, toJsonObject(v)); + } + return array; + } + + template::value>::type> + static json_object* toJsonObject(const T& value) + { + ToJsonVisitor visitor; + value.accept(visitor); + return visitor.detach(); + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_TO_JSON_VISITOR_HPP diff --git a/common/config/to-kvstore-visitor.hpp b/common/config/to-kvstore-visitor.hpp new file mode 100644 index 0000000..14944dc --- /dev/null +++ b/common/config/to-kvstore-visitor.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak (j.olszak@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Visitor for saving to KVStore + */ + +#ifndef COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP +#define COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP + +#include "config/is-visitable.hpp" +#include "config/kvstore.hpp" + +namespace config { + +class ToKVStoreVisitor { + +public: + ToKVStoreVisitor(KVStore& store, const std::string& prefix) + : mStore(store), + mKeyPrefix(prefix) + { + } + + ToKVStoreVisitor& operator=(const ToKVStoreVisitor&) = delete; + + template + void visit(const std::string& name, const T& value) + { + setInternal(key(mKeyPrefix, name), value); + } + +private: + KVStore& mStore; + std::string mKeyPrefix; + + ToKVStoreVisitor(const ToKVStoreVisitor& visitor, const std::string& prefix) + : mStore(visitor.mStore), + mKeyPrefix(prefix) + { + } + + template::value, int>::type = 0> + void setInternal(const std::string& name, const T& value) + { + mStore.set(name, value); + } + + template::value, int>::type = 0> + void setInternal(const std::string& name, const T& value) + { + ToKVStoreVisitor visitor(*this, name); + value.accept(visitor); + } + + template::value, int>::type = 0> + void setInternal(const std::string& name, const std::vector& values) + { + mStore.remove(name); + mStore.set(name, values.size()); + for (size_t i = 0; i < values.size(); ++i) { + setInternal(key(name, std::to_string(i)), values[i]); + } + } +}; + +} // namespace config + +#endif // COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP diff --git a/common/dbus/connection.cpp b/common/dbus/connection.cpp new file mode 100644 index 0000000..12544be --- /dev/null +++ b/common/dbus/connection.cpp @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Dbus connection class + */ + +#include "config.hpp" +#include "dbus/connection.hpp" +#include "dbus/exception.hpp" +#include "utils/callback-wrapper.hpp" +#include "utils/scoped-gerror.hpp" +#include "utils/glib-utils.hpp" +#include "logger/logger.hpp" + +using namespace vasum::utils; + +namespace dbus { + + +namespace { + +const std::string SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket"; +const std::string INTROSPECT_INTERFACE = "org.freedesktop.DBus.Introspectable"; +const std::string INTROSPECT_METHOD = "Introspect"; + +class MethodResultBuilderImpl : public MethodResultBuilder { +public: + MethodResultBuilderImpl(GDBusMethodInvocation* invocation) + : mInvocation(invocation), mResultSet(false) {} + ~MethodResultBuilderImpl() + { + if (!mResultSet) { + setError("org.freedesktop.DBus.Error.UnknownMethod", "Not implemented"); + } + } + void set(GVariant* parameters) + { + g_dbus_method_invocation_return_value(mInvocation, parameters); + mResultSet = true; + } + void setVoid() + { + set(NULL); + } + void setError(const std::string& name, const std::string& message) + { + g_dbus_method_invocation_return_dbus_error(mInvocation, name.c_str(), message.c_str()); + mResultSet = true; + } +private: + GDBusMethodInvocation* mInvocation; + bool mResultSet; +}; + +void throwDbusException(const ScopedGError& e) +{ + if (e->domain == g_io_error_quark()) { + if (e->code == G_IO_ERROR_DBUS_ERROR) { + throw DbusCustomException(e->message); + } else { + throw DbusIOException(e->message); + } + } else if (e->domain == g_dbus_error_quark()) { + throw DbusOperationException(e->message); + } else if (e->domain == g_markup_error_quark()) { + throw DbusInvalidArgumentException(e->message); + } else { + throw DbusException(e->message); + } +} + +class AsyncMethodCallResultImpl : public AsyncMethodCallResult { +public: + AsyncMethodCallResultImpl(GVariant* result, const ScopedGError& error) + : mResult(result), mError(error) {} + ~AsyncMethodCallResultImpl() + { + if (mResult) { + g_variant_unref(mResult); + } + } + GVariant* get() + { + if (mError) { + throwDbusException(mError); + } + return mResult; + } +private: + GVariant* mResult; + const ScopedGError& mError; +}; + +} // namespace + +DbusConnection::Pointer DbusConnection::create(const std::string& address) +{ + return Pointer(new DbusConnection(address)); +} + +DbusConnection::Pointer DbusConnection::createSystem() +{ + return create(SYSTEM_BUS_ADDRESS); +} + +DbusConnection::DbusConnection(const std::string& address) + : mConnection(NULL) + , mNameId(0) +{ + ScopedGError error; + const GDBusConnectionFlags flags = + static_cast(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | + G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION); + // TODO: this is possible deadlock if the dbus + // socket exists but there is no dbus-daemon + mConnection = g_dbus_connection_new_for_address_sync(address.c_str(), + flags, + NULL, + NULL, + &error); + if (error) { + error.strip(); + LOGE("Could not connect to " << address << "; " << error); + throwDbusException(error); + } +} + +DbusConnection::~DbusConnection() +{ + // Close connection in a glib thread (because of a bug in glib) + GDBusConnection* connection = mConnection; + guint nameId = mNameId; + + auto closeConnection = [=]() { + if (nameId) { + g_bus_unown_name(nameId); + } + g_object_unref(connection); + LOGT("Connection deleted"); + }; + executeInGlibThread(closeConnection, mGuard); +} + +void DbusConnection::setName(const std::string& name, + const VoidCallback& onNameAcquired, + const VoidCallback& onNameLost) +{ + mNameId = g_bus_own_name_on_connection(mConnection, + name.c_str(), + G_BUS_NAME_OWNER_FLAGS_NONE, + &DbusConnection::onNameAcquired, + &DbusConnection::onNameLost, + createCallbackWrapper( + NameCallbacks(onNameAcquired, onNameLost), + mGuard.spawn()), + &deleteCallbackWrapper); +} + +void DbusConnection::onNameAcquired(GDBusConnection*, const gchar* name, gpointer userData) +{ + LOGD("Name acquired " << name); + const NameCallbacks& callbacks = getCallbackFromPointer(userData); + if (callbacks.nameAcquired) { + callbacks.nameAcquired(); + } +} + +void DbusConnection::onNameLost(GDBusConnection*, const gchar* name, gpointer userData) +{ + LOGD("Name lost " << name); + const NameCallbacks& callbacks = getCallbackFromPointer(userData); + if (callbacks.nameLost) { + callbacks.nameLost(); + } +} + +void DbusConnection::emitSignal(const std::string& objectPath, + const std::string& interface, + const std::string& name, + GVariant* parameters) +{ + ScopedGError error; + g_dbus_connection_emit_signal(mConnection, + NULL, + objectPath.c_str(), + interface.c_str(), + name.c_str(), + parameters, + &error); + if (error) { + error.strip(); + LOGE("Emit signal failed; " << error); + throwDbusException(error); + } +} + +DbusConnection::SubscriptionId DbusConnection::signalSubscribe(const SignalCallback& callback, + const std::string& senderBusName) +{ + return g_dbus_connection_signal_subscribe(mConnection, + senderBusName.empty() ? NULL : senderBusName.c_str(), + NULL, + NULL, + NULL, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + &DbusConnection::onSignal, + createCallbackWrapper(callback, + mGuard.spawn()), + &deleteCallbackWrapper); +} + +void DbusConnection::signalUnsubscribe(DbusConnection::SubscriptionId subscriptionId) +{ + g_dbus_connection_signal_unsubscribe(mConnection, subscriptionId); +} + +void DbusConnection::onSignal(GDBusConnection*, + const gchar* sender, + const gchar* object, + const gchar* interface, + const gchar* name, + GVariant* parameters, + gpointer userData) +{ + const SignalCallback& callback = getCallbackFromPointer(userData); + + LOGD("Signal: " << sender << "; " << object << "; " << interface << "; " << name); + + if (callback) { + callback(sender, object, interface, name, parameters); + } +} + +std::string DbusConnection::introspect(const std::string& busName, const std::string& objectPath) +{ + GVariantPtr result = DbusConnection::callMethod(busName, + objectPath, + INTROSPECT_INTERFACE, + INTROSPECT_METHOD, + NULL, + "(s)"); + const gchar* xml; + g_variant_get(result.get(), "(&s)", &xml); + return xml; +} + +void DbusConnection::registerObject(const std::string& objectPath, + const std::string& objectDefinitionXml, + const MethodCallCallback& callback) +{ + ScopedGError error; + GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(objectDefinitionXml.c_str(), &error); + if (nodeInfo != NULL && (nodeInfo->interfaces == NULL || + nodeInfo->interfaces[0] == NULL || + nodeInfo->interfaces[1] != NULL)) { + g_dbus_node_info_unref(nodeInfo); + g_set_error(&error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Expected exactly one interface"); + } + if (error) { + error.strip(); + LOGE("Invalid xml; " << error); + throwDbusException(error); + } + GDBusInterfaceInfo* interfaceInfo = nodeInfo->interfaces[0]; + + GDBusInterfaceVTable vtable; + vtable.method_call = &DbusConnection::onMethodCall; + vtable.get_property = NULL; + vtable.set_property = NULL; + + g_dbus_connection_register_object(mConnection, + objectPath.c_str(), + interfaceInfo, + &vtable, + createCallbackWrapper(callback, mGuard.spawn()), + &deleteCallbackWrapper, + &error); + g_dbus_node_info_unref(nodeInfo); + if (error) { + error.strip(); + LOGE("Register object failed; " << error); + throwDbusException(error); + } +} + +void DbusConnection::onMethodCall(GDBusConnection*, + const gchar*, + const gchar* objectPath, + const gchar* interface, + const gchar* method, + GVariant* parameters, + GDBusMethodInvocation* invocation, + gpointer userData) +{ + const MethodCallCallback& callback = getCallbackFromPointer(userData); + + LOGD("MethodCall: " << objectPath << "; " << interface << "; " << method); + + MethodResultBuilder::Pointer resultBuilder(new MethodResultBuilderImpl(invocation)); + if (callback) { + callback(objectPath, interface, method, parameters, resultBuilder); + } +} + +GVariantPtr DbusConnection::callMethod(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + int timeoutMs) +{ + ScopedGError error; + GVariant* result = g_dbus_connection_call_sync(mConnection, + busName.c_str(), + objectPath.c_str(), + interface.c_str(), + method.c_str(), + parameters, + replyType.empty() ? NULL + : G_VARIANT_TYPE(replyType.c_str()), + G_DBUS_CALL_FLAGS_NONE, + timeoutMs, + NULL, + &error); + if (error) { + error.strip(); + LOGE("Call method failed; " << error); + throwDbusException(error); + } + return GVariantPtr(result, g_variant_unref); +} + +void DbusConnection::callMethodAsync(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + const AsyncMethodCallCallback& callback, + int timeoutMs) +{ + g_dbus_connection_call(mConnection, + busName.c_str(), + objectPath.c_str(), + interface.c_str(), + method.c_str(), + parameters, + replyType.empty() ? NULL + : G_VARIANT_TYPE(replyType.c_str()), + G_DBUS_CALL_FLAGS_NONE, + timeoutMs, + NULL, + &DbusConnection::onAsyncReady, + createCallbackWrapper(callback, mGuard.spawn())); +} + +void DbusConnection::onAsyncReady(GObject* source, + GAsyncResult* asyncResult, + gpointer userData) +{ + std::unique_ptr + autoDeleteCallback(userData, &deleteCallbackWrapper); + GDBusConnection* connection = reinterpret_cast(source); + const AsyncMethodCallCallback& callback = + getCallbackFromPointer(userData); + + ScopedGError error; + GVariant* result = g_dbus_connection_call_finish(connection, asyncResult, &error); + if (error) { + error.strip(); + LOGE("Call method failed; " << error); + } + AsyncMethodCallResultImpl asyncMethodCallResult(result, error); + if (callback) { + try { + callback(asyncMethodCallResult); + } catch (DbusException& e) { + // Drop dbus exceptions (thrown from asyncMethodCallResult.get()). + // We can not ignore other exceptions - they must be catched inside callback, + // otherwise std::terminate will be called. + LOGW("Uncaugth dbus exception: " << e.what()); + } + } +} + +} // namespace dbus diff --git a/common/dbus/connection.hpp b/common/dbus/connection.hpp new file mode 100644 index 0000000..6603c9d --- /dev/null +++ b/common/dbus/connection.hpp @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Dbus connection class + */ + +#ifndef COMMON_DBUS_CONNECTION_HPP +#define COMMON_DBUS_CONNECTION_HPP + +#include "utils/callback-guard.hpp" + +#include +#include +#include +#include + + +namespace dbus { + + +typedef std::unique_ptr GVariantPtr; + +/** + * An interface used to set a result to a method call. + */ +class MethodResultBuilder { +public: + typedef std::shared_ptr Pointer; + + virtual ~MethodResultBuilder() {} + virtual void set(GVariant* parameters) = 0; + virtual void setVoid() = 0; + virtual void setError(const std::string& name, const std::string& message) = 0; +}; + +/** + * An interface used to get result from async response. + */ +class AsyncMethodCallResult { +public: + virtual ~AsyncMethodCallResult() {} + virtual GVariant* get() = 0; // throws DbusException on error +}; + +/** + * Dbus connection. + * Provides a functionality that allows to call dbus methods, + * register dbus interfaces, etc. + * + * TODO divide to interface and implementation header + */ +class DbusConnection { +public: + typedef std::unique_ptr Pointer; + + typedef std::function VoidCallback; + + typedef std::function MethodCallCallback; + + typedef std::function SignalCallback; + + typedef std::function AsyncMethodCallCallback; + + typedef unsigned int SubscriptionId; + + /** + * Creates a connection to the dbus with given address. + */ + static Pointer create(const std::string& address); + + /** + * Creates a connection to the system dbus. + */ + static Pointer createSystem(); + + ~DbusConnection(); + + /** + * Sets a name to the dbus connection. + * It allows other client to call methods using this name. + */ + void setName(const std::string& name, + const VoidCallback& onNameAcquired, + const VoidCallback& onNameLost); + + /** + * Emits dbus signal. + */ + void emitSignal(const std::string& objectPath, + const std::string& interface, + const std::string& name, + GVariant* parameters); + + /** + * Subscribes to a signal. + * Empty sender means subscribe to all signals + * Returns a subscription identifier that can be used to unsubscribe signal + */ + SubscriptionId signalSubscribe(const SignalCallback& callback, const std::string& senderBusName); + + /** + * Unsubscribes from a signal. + */ + void signalUnsubscribe(SubscriptionId subscriptionId); + + /** + * Registers an object with given definition. + * Api calls will be handled by given callback. + */ + void registerObject(const std::string& objectPath, + const std::string& objectDefinitionXml, + const MethodCallCallback& callback); + + /** + * Call a dbus method + */ + GVariantPtr callMethod(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + int timeoutMs = -1); + + /** + * Async call a dbus method + */ + void callMethodAsync(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + const AsyncMethodCallCallback& callback, + int timeoutMs = -1); + + /** + * Returns an xml with meta description of specified dbus object. + */ + std::string introspect(const std::string& busName, const std::string& objectPath); + +private: + struct NameCallbacks { + VoidCallback nameAcquired; + VoidCallback nameLost; + + NameCallbacks(const VoidCallback& acquired, const VoidCallback& lost) + : nameAcquired(acquired), nameLost(lost) {} + }; + + vasum::utils::CallbackGuard mGuard; + GDBusConnection* mConnection; + guint mNameId; + + DbusConnection(const std::string& address); + + static void onNameAcquired(GDBusConnection* connection, const gchar* name, gpointer userData); + static void onNameLost(GDBusConnection* connection, const gchar* name, gpointer userData); + static void onSignal(GDBusConnection* connection, + const gchar* sender, + const gchar* object, + const gchar* interface, + const gchar* name, + GVariant* parameters, + gpointer userData); + static void onMethodCall(GDBusConnection* connection, + const gchar* sender, + const gchar* objectPath, + const gchar* interface, + const gchar* method, + GVariant* parameters, + GDBusMethodInvocation* invocation, + gpointer userData); + static void onAsyncReady(GObject* source, + GAsyncResult* asyncResult, + gpointer userData); +}; + + +} // namespace dbus + +#endif // COMMON_DBUS_CONNECTION_HPP diff --git a/common/dbus/exception.hpp b/common/dbus/exception.hpp new file mode 100644 index 0000000..a09bdbc --- /dev/null +++ b/common/dbus/exception.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Dbus exceptions + */ + +#ifndef COMMON_DBUS_EXCEPTION_HPP +#define COMMON_DBUS_EXCEPTION_HPP + +#include + +namespace dbus { + +/** + * Base class for dbus exceptions + */ +struct DbusException: public std::runtime_error { + + DbusException(const std::string& error = "") : std::runtime_error(error) {} +}; + +/** + * Dbus IO exception (connection failed, connection lost, etc) + */ +struct DbusIOException: public DbusException { + + DbusIOException(const std::string& error = "") : DbusException(error) {} +}; + +/** + * Dbus operation failed exception + */ +struct DbusOperationException: public DbusException { + + DbusOperationException(const std::string& error = "") : DbusException(error) {} +}; + +/** + * Dbus custom exception triggered by user logic + */ +struct DbusCustomException: public DbusException { + + DbusCustomException(const std::string& error = "") : DbusException(error) {} +}; + +/** + * Dbus invalid argument exception + */ +struct DbusInvalidArgumentException: public DbusException { + + DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {} +}; + +} // namespace dbus + +#endif // COMMON_DBUS_EXCEPTION_HPP diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index a3342b6..db15a4a 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -38,7 +38,7 @@ namespace ipc { /** * This class wraps communication via UX sockets for client applications. - * It uses serialization mechanism from libConfig. + * It uses serialization mechanism from Config. * * For message format @see ipc::Processor */ diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index dec16e8..84aaa5c 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -62,7 +62,7 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500; * This class wraps communication via UX sockets * * It's intended to be used both in Client and Service classes. -* It uses a serialization mechanism from libConfig. +* It uses a serialization mechanism from Config. * Library user will only have to pass the types that each call will send and receive * * Message format: diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 880c137..32b604f 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -40,7 +40,7 @@ namespace ipc { /** * This class wraps communication via UX sockets. - * It uses serialization mechanism from libConfig. + * It uses serialization mechanism from Config. * * For message format @see ipc::Processor */ diff --git a/common/logger/backend-journal.cpp b/common/logger/backend-journal.cpp new file mode 100644 index 0000000..12c4eff --- /dev/null +++ b/common/logger/backend-journal.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Systemd journal backend for logger + */ + +#include "config.hpp" +#include "logger/backend-journal.hpp" + +#define SD_JOURNAL_SUPPRESS_LOCATION +#include + +namespace logger { + +namespace { + +inline int toJournalPriority(LogLevel logLevel) +{ + switch (logLevel) { + case LogLevel::ERROR: + return LOG_ERR; // 3 + case LogLevel::WARN: + return LOG_WARNING; // 4 + case LogLevel::INFO: + return LOG_INFO; // 6 + case LogLevel::DEBUG: + return LOG_DEBUG; // 7 + case LogLevel::TRACE: + return LOG_DEBUG; // 7 + case LogLevel::HELP: + return LOG_DEBUG; // 7 + default: + return LOG_DEBUG; // 7 + } +} + +} // namespace + +void SystemdJournalBackend::log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) +{ + sd_journal_send("PRIORITY=%d", toJournalPriority(logLevel), + "CODE_FILE=%s", file.c_str(), + "CODE_LINE=%d", line, + "CODE_FUNC=%s", func.c_str(), + "MESSAGE=%s", message.c_str(), + NULL); +} + +} // namespace logger diff --git a/common/logger/backend-journal.hpp b/common/logger/backend-journal.hpp new file mode 100644 index 0000000..e566ed1 --- /dev/null +++ b/common/logger/backend-journal.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Systemd journal backend for logger + */ + +#ifndef COMMON_LOGGER_BACKEND_JOURNAL_HPP +#define COMMON_LOGGER_BACKEND_JOURNAL_HPP + +#include "logger/backend.hpp" + +namespace logger { + +/** + * systemd journal logging backend + */ +class SystemdJournalBackend : public LogBackend { +public: + void log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) override; +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_JOURNAL_HPP diff --git a/common/logger/backend-null.hpp b/common/logger/backend-null.hpp new file mode 100644 index 0000000..4a7e8a9 --- /dev/null +++ b/common/logger/backend-null.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Pawel Broda + * + * 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 Pawel Broda (p.broda@partner.samsung.com) + * @brief Null backend for logger + */ + +#ifndef COMMON_LOGGER_BACKEND_NULL_HPP +#define COMMON_LOGGER_BACKEND_NULL_HPP + +#include "logger/backend.hpp" + +namespace logger { + +/** + * Null logging backend + */ +class NullLogger : public LogBackend { +public: + void log(LogLevel /*logLevel*/, + const std::string& /*file*/, + const unsigned int& /*line*/, + const std::string& /*func*/, + const std::string& /*message*/) override {} +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_NULL_HPP diff --git a/common/logger/backend-stderr.cpp b/common/logger/backend-stderr.cpp new file mode 100644 index 0000000..d4e36b1 --- /dev/null +++ b/common/logger/backend-stderr.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Pawel Broda + * + * 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 Pawel Broda (p.broda@partner.samsung.com) + * @brief Stderr backend for logger + */ + +#include "config.hpp" +#include "logger/backend-stderr.hpp" +#include "logger/formatter.hpp" + +#include + +namespace logger { + +void StderrBackend::log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) +{ + typedef boost::char_separator charSeparator; + typedef boost::tokenizer tokenizer; + + // example log string + // 06:52:35.123 [ERROR] src/util/fs.cpp:43 readFileContent: /file/file.txt is missing + + const std::string logColor = LogFormatter::getConsoleColor(logLevel); + const std::string defaultColor = LogFormatter::getDefaultConsoleColor(); + const std::string header = LogFormatter::getHeader(logLevel, file, line, func); + tokenizer tokens(message, charSeparator("\n")); + for (const auto& messageLine : tokens) { + if (!messageLine.empty()) { + fprintf(stderr, + "%s%s%s%s\n", + logColor.c_str(), + header.c_str(), + messageLine.c_str(), + defaultColor.c_str()); + } + } +} + +} // namespace logger diff --git a/common/logger/backend-stderr.hpp b/common/logger/backend-stderr.hpp new file mode 100644 index 0000000..4cdd0ec --- /dev/null +++ b/common/logger/backend-stderr.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Pawel Broda + * + * 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 Pawel Broda (p.broda@partner.samsung.com) + * @brief Stderr backend for logger + */ + +#ifndef COMMON_LOGGER_BACKEND_STDERR_HPP +#define COMMON_LOGGER_BACKEND_STDERR_HPP + +#include "logger/backend.hpp" + +namespace logger { + +/** + * Stderr logging backend + */ +class StderrBackend : public LogBackend { +public: + void log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) override; +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_STDERR_HPP diff --git a/common/logger/backend.hpp b/common/logger/backend.hpp new file mode 100644 index 0000000..99b0c49 --- /dev/null +++ b/common/logger/backend.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Pawel Broda + * + * 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 Pawel Broda (p.broda@partner.samsung.com) + * @brief Logging backend + */ + +#ifndef COMMON_LOGGER_BACKEND_HPP +#define COMMON_LOGGER_BACKEND_HPP + +#include "logger/level.hpp" + +#include + +namespace logger { + +/** + * Abstract class for logger + */ +class LogBackend { +public: + virtual void log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) = 0; + virtual ~LogBackend() {} +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_HPP diff --git a/common/logger/ccolor.cpp b/common/logger/ccolor.cpp new file mode 100644 index 0000000..e5e71b0 --- /dev/null +++ b/common/logger/ccolor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Console color for StderrBackend logger + */ + +#include "config.hpp" +#include "logger/ccolor.hpp" + +#include + +namespace logger { + +std::string getConsoleEscapeSequence(Attributes attr, Color color) +{ + char command[10]; + + // Command is the control command to the terminal + snprintf(command, sizeof(command), "%c[%d;%dm", 0x1B, attr, color); + return std::string(command); +} + +} // namespace logger diff --git a/common/logger/ccolor.hpp b/common/logger/ccolor.hpp new file mode 100644 index 0000000..47cc25e --- /dev/null +++ b/common/logger/ccolor.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Console color for StderrBackend logger + */ + +#ifndef COMMON_LOGGER_CCOLOR_HPP +#define COMMON_LOGGER_CCOLOR_HPP + +#include + +namespace logger { + +enum class Color : unsigned int { + DEFAULT = 0, + BLACK = 90, + RED = 91, + GREEN = 92, + YELLOW = 93, + BLUE = 94, + MAGENTA = 95, + CYAN = 96, + WHITE = 97 +}; + +enum class Attributes : unsigned int { + DEFAULT = 0, + BOLD = 1 +}; + +std::string getConsoleEscapeSequence(Attributes attr, Color color); + +} // namespace logger + +#endif // COMMON_LOGGER_CCOLOR_HPP diff --git a/common/logger/formatter.cpp b/common/logger/formatter.cpp new file mode 100644 index 0000000..529cd14 --- /dev/null +++ b/common/logger/formatter.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Helper formatter for logger + */ + +#include "config.hpp" +#include "logger/formatter.hpp" +#include "logger/ccolor.hpp" + +#include +#include +#include +#include +#include +#include + +namespace logger { + +namespace { + +const int TIME_COLUMN_LENGTH = 12; +const int SEVERITY_COLUMN_LENGTH = 8; +const int THREAD_COLUMN_LENGTH = 3; +const int FILE_COLUMN_LENGTH = 60; + +std::atomic gNextThreadId(1); +thread_local unsigned int gThisThreadId(0); + +} // namespace + +unsigned int LogFormatter::getCurrentThread(void) +{ + unsigned int id = gThisThreadId; + if (id == 0) { + gThisThreadId = id = gNextThreadId++; + } + + return id; +} + +std::string LogFormatter::getCurrentTime(void) +{ + char time[TIME_COLUMN_LENGTH + 1]; + struct timeval tv; + gettimeofday(&tv, NULL); + struct tm* tm = localtime(&tv.tv_sec); + snprintf(time, + sizeof(time), + "%02d:%02d:%02d.%03d", + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + int(tv.tv_usec / 1000)); + + return std::string(time); +} + +std::string LogFormatter::getConsoleColor(LogLevel logLevel) +{ + switch (logLevel) { + case LogLevel::ERROR: + return getConsoleEscapeSequence(Attributes::BOLD, Color::RED); + case LogLevel::WARN: + return getConsoleEscapeSequence(Attributes::BOLD, Color::YELLOW); + case LogLevel::INFO: + return getConsoleEscapeSequence(Attributes::BOLD, Color::BLUE); + case LogLevel::DEBUG: + return getConsoleEscapeSequence(Attributes::DEFAULT, Color::GREEN); + case LogLevel::TRACE: + return getConsoleEscapeSequence(Attributes::DEFAULT, Color::BLACK); + case LogLevel::HELP: + return getConsoleEscapeSequence(Attributes::BOLD, Color::MAGENTA); + default: + return getConsoleEscapeSequence(Attributes::DEFAULT, Color::DEFAULT); + } +} + +std::string LogFormatter::getDefaultConsoleColor(void) +{ + return getConsoleEscapeSequence(Attributes::DEFAULT, Color::DEFAULT); +} + +std::string LogFormatter::stripProjectDir(const std::string& file, + const std::string& rootDir) +{ + // If rootdir is empty then return full name + if (rootDir.empty()) { + return file; + } + const std::string sourceDir = rootDir + "/"; + // If file does not belong to rootDir then also return full name + if (0 != file.compare(0, sourceDir.size(), sourceDir)) { + return file; + } + return file.substr(sourceDir.size()); +} + +std::string LogFormatter::getHeader(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func) +{ + std::ostringstream logLine; + logLine << getCurrentTime() << ' ' + << std::left << std::setw(SEVERITY_COLUMN_LENGTH) << '[' + toString(logLevel) + ']' + << std::right << std::setw(THREAD_COLUMN_LENGTH) << getCurrentThread() << ": " + << std::left << std::setw(FILE_COLUMN_LENGTH) + << file + ':' + std::to_string(line) + ' ' + func + ':'; + return logLine.str(); +} + +} // namespace logger diff --git a/common/logger/formatter.hpp b/common/logger/formatter.hpp new file mode 100644 index 0000000..3af0763 --- /dev/null +++ b/common/logger/formatter.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk + * + * 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 Dariusz Michaluk (d.michaluk@samsung.com) + * @brief Helper formatter for logger + */ + +#ifndef COMMON_LOGGER_FORMATTER_HPP +#define COMMON_LOGGER_FORMATTER_HPP + +#include "logger/level.hpp" + +#include + +namespace logger { + +class LogFormatter { +public: + static unsigned int getCurrentThread(void); + static std::string getCurrentTime(void); + static std::string getConsoleColor(LogLevel logLevel); + static std::string getDefaultConsoleColor(void); + static std::string stripProjectDir(const std::string& file, + const std::string& rootDir); + static std::string getHeader(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func); +}; + +} // namespace logger + +#endif // COMMON_LOGGER_FORMATTER_HPP diff --git a/common/logger/level.cpp b/common/logger/level.cpp new file mode 100644 index 0000000..bf46561 --- /dev/null +++ b/common/logger/level.cpp @@ -0,0 +1,71 @@ +/* + * 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 Functions to handle LogLevel + */ + +#include "config.hpp" +#include "logger/level.hpp" + +#include +#include + +namespace logger { + +LogLevel parseLogLevel(const std::string& level) +{ + if (boost::iequals(level, "ERROR")) { + return LogLevel::ERROR; + } else if (boost::iequals(level, "WARN")) { + return LogLevel::WARN; + } else if (boost::iequals(level, "INFO")) { + return LogLevel::INFO; + } else if (boost::iequals(level, "DEBUG")) { + return LogLevel::DEBUG; + } else if (boost::iequals(level, "TRACE")) { + return LogLevel::TRACE; + } else if (boost::iequals(level, "HELP")) { + return LogLevel::HELP; + } else { + throw std::runtime_error("Invalid LogLevel to parse"); + } +} + +std::string toString(const LogLevel logLevel) +{ + switch (logLevel) { + case LogLevel::ERROR: + return "ERROR"; + case LogLevel::WARN: + return "WARN"; + case LogLevel::INFO: + return "INFO"; + case LogLevel::DEBUG: + return "DEBUG"; + case LogLevel::TRACE: + return "TRACE"; + case LogLevel::HELP: + return "HELP"; + default: + return "UNKNOWN"; + } +} +} // namespace logger diff --git a/common/logger/level.hpp b/common/logger/level.hpp new file mode 100644 index 0000000..7902301 --- /dev/null +++ b/common/logger/level.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Dariusz Michaluk (d.michaluk@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Dariusz Michaluk (d.michaluk@samsung.com) + * @brief LogLevel + */ + +#ifndef COMMON_LOGGER_LEVEL_HPP +#define COMMON_LOGGER_LEVEL_HPP + +#include + +namespace logger { + +enum class LogLevel { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + HELP +}; + +/** + * @param logLevel LogLevel + * @return std::sting representation of the LogLevel value + */ +std::string toString(const LogLevel logLevel); + +/** + * @param level string representation of log level + * @return parsed LogLevel value + */ +LogLevel parseLogLevel(const std::string& level); + +} // namespace logger + +#endif // COMMON_LOGGER_LEVEL_HPP diff --git a/common/logger/logger-scope.cpp b/common/logger/logger-scope.cpp new file mode 100644 index 0000000..e790bab --- /dev/null +++ b/common/logger/logger-scope.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * 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 Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Scope logger class implementation + */ + +#include "logger/logger-scope.hpp" +#include "logger/logger.hpp" + +namespace logger { + +SStreamWrapper::operator std::string() const +{ + return mSStream.str(); +} + +LoggerScope::LoggerScope(const std::string& file, + const unsigned int line, + const std::string& func, + const std::string& message, + const std::string& rootDir): + mFile(file), + mLine(line), + mFunc(func), + mMessage(message), + mRootDir(rootDir) +{ + logger::Logger::logMessage(logger::LogLevel::TRACE, "Entering: " + mMessage, mFile, + mLine, mFunc, mRootDir); +} + +LoggerScope::~LoggerScope() +{ + logger::Logger::logMessage(logger::LogLevel::TRACE, "Leaving: " + mMessage, mFile, + mLine, mFunc, mRootDir); +} + +} // namespace logger diff --git a/common/logger/logger-scope.hpp b/common/logger/logger-scope.hpp new file mode 100644 index 0000000..cefd912 --- /dev/null +++ b/common/logger/logger-scope.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * 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 Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Scope logger class declaration + */ + +#ifndef COMMON_LOGGER_LOGGER_SCOPE_HPP +#define COMMON_LOGGER_LOGGER_SCOPE_HPP + +#include +#include + +namespace logger { + +class SStreamWrapper +{ +public: + operator std::string() const; + + template + SStreamWrapper& operator<<(const T& b) + { + this->mSStream << b; + return *this; + } + +private: + std::ostringstream mSStream; +}; + +/** + * Class specifically for scope debug logging. Should be used at the beggining of a scope. + * Constructor marks scope enterance, destructor marks scope leave. + */ +class LoggerScope +{ +public: + LoggerScope(const std::string& file, + const unsigned int line, + const std::string& func, + const std::string& message, + const std::string& rootDir); + ~LoggerScope(); + +private: + const std::string mFile; + const unsigned int mLine; + const std::string mFunc; + const std::string mMessage; + const std::string mRootDir; +}; + +} // namespace logger + +// macro to automatically create LoggerScope object +#define LOGS(MSG) logger::LoggerScope logScopeObj(__FILE__, __LINE__, __func__, \ + logger::SStreamWrapper() << MSG, \ + PROJECT_SOURCE_DIR) + +#endif // COMMON_LOGGER_LOGGER_SCOPE_HPP diff --git a/common/logger/logger.cpp b/common/logger/logger.cpp new file mode 100644 index 0000000..aa2dccd --- /dev/null +++ b/common/logger/logger.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Pawel Broda + * + * 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 Pawel Broda (p.broda@partner.samsung.com) + * @brief Logger + */ + +#include "config.hpp" +#include "logger/logger.hpp" +#include "logger/formatter.hpp" +#include "logger/backend-null.hpp" + +#include +#include + +namespace logger { + +namespace { + +volatile LogLevel gLogLevel = LogLevel::DEBUG; +std::unique_ptr gLogBackendPtr(new NullLogger()); +std::mutex gLogMutex; + +} // namespace + +void Logger::logMessage(LogLevel logLevel, + const std::string& message, + const std::string& file, + const unsigned int line, + const std::string& func, + const std::string& rootDir) +{ + std::string sfile = LogFormatter::stripProjectDir(file, rootDir); + std::unique_lock lock(gLogMutex); + gLogBackendPtr->log(logLevel, sfile, line, func, message); +} + +void Logger::setLogLevel(const LogLevel level) +{ + gLogLevel = level; +} + +void Logger::setLogLevel(const std::string& level) +{ + gLogLevel = parseLogLevel(level); +} + +LogLevel Logger::getLogLevel(void) +{ + return gLogLevel; +} + +void Logger::setLogBackend(LogBackend* pBackend) +{ + std::unique_lock lock(gLogMutex); + gLogBackendPtr.reset(pBackend); +} + +} // namespace logger diff --git a/common/logger/logger.hpp b/common/logger/logger.hpp new file mode 100644 index 0000000..8d8d433 --- /dev/null +++ b/common/logger/logger.hpp @@ -0,0 +1,79 @@ +/* + * 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 Logger + */ + +#ifndef COMMON_LOGGER_LOGGER_HPP +#define COMMON_LOGGER_LOGGER_HPP + +#include "logger/level.hpp" + +#include +#include + +#ifndef PROJECT_SOURCE_DIR +#define PROJECT_SOURCE_DIR "" +#endif + +namespace logger { + +class LogBackend; + +class Logger { +public: + static void logMessage(LogLevel logLevel, + const std::string& message, + const std::string& file, + const unsigned int line, + const std::string& func, + const std::string& rootDir); + + static void setLogLevel(const LogLevel level); + static void setLogLevel(const std::string& level); + static LogLevel getLogLevel(void); + static void setLogBackend(LogBackend* pBackend); +}; + +} // namespace logger + +#define LOG(SEVERITY, MESSAGE) \ + do { \ + if (logger::Logger::getLogLevel() <= logger::LogLevel::SEVERITY) { \ + std::ostringstream messageStream__; \ + messageStream__ << MESSAGE; \ + logger::Logger::logMessage(logger::LogLevel::SEVERITY, \ + messageStream__.str(), \ + __FILE__, \ + __LINE__, \ + __func__, \ + PROJECT_SOURCE_DIR); \ + } \ + } while (0) + +#define LOGE(MESSAGE) LOG(ERROR, MESSAGE) +#define LOGW(MESSAGE) LOG(WARN, MESSAGE) +#define LOGI(MESSAGE) LOG(INFO, MESSAGE) +#define LOGD(MESSAGE) LOG(DEBUG, MESSAGE) +#define LOGH(MESSAGE) LOG(HELP, MESSAGE) +#define LOGT(MESSAGE) LOG(TRACE, MESSAGE) + +#endif // COMMON_LOGGER_LOGGER_HPP diff --git a/common/netlink/netlink-message.hpp b/common/netlink/netlink-message.hpp index 971e6ad..3379009 100644 --- a/common/netlink/netlink-message.hpp +++ b/common/netlink/netlink-message.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace vasum { diff --git a/common/utils/glib-utils.cpp b/common/utils/glib-utils.cpp new file mode 100644 index 0000000..93cbff9 --- /dev/null +++ b/common/utils/glib-utils.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief C++ wrapper of glib main loop + */ + +#include "config.hpp" +#include "utils/glib-utils.hpp" +#include "utils/callback-wrapper.hpp" + +#include + +namespace vasum { +namespace utils { + +namespace { + +gboolean onIddle(gpointer data) +{ + const VoidCallback& callback = getCallbackFromPointer(data); + callback(); + return FALSE; +} + +} // namespace + +void executeInGlibThread(const VoidCallback& callback, const CallbackGuard& guard) +{ + if (!callback) { + return; + } + g_idle_add_full(G_PRIORITY_DEFAULT, + &onIddle, + utils::createCallbackWrapper(callback, guard.spawn()), + &utils::deleteCallbackWrapper); + +} + + +} // namespace utils +} // namespace vasum diff --git a/common/utils/glib-utils.hpp b/common/utils/glib-utils.hpp new file mode 100644 index 0000000..eaeeee8 --- /dev/null +++ b/common/utils/glib-utils.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Miscellaneous helpers for the Glib library + */ + +#ifndef COMMON_UTILS_GLIB_UTILS_HPP +#define COMMON_UTILS_GLIB_UTILS_HPP + +#include "utils/callback-guard.hpp" + +namespace vasum { +namespace utils { + +typedef std::function VoidCallback; + +/** + * Executes a callback in glib thread (adds an iddle event to glib) + */ +void executeInGlibThread(const VoidCallback& callback, const CallbackGuard& guard); + + +} // namespace utils +} // namespace vasum + +#endif // COMMON_UTILS_GLIB_UTILS_HPP diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 6cea869..bd31d68 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -21,9 +21,6 @@ BuildRequires: boost-devel BuildRequires: libjson-devel >= 0.10 BuildRequires: libcap-ng-devel BuildRequires: lxc-devel -BuildRequires: pkgconfig(libConfig) -BuildRequires: pkgconfig(libLogger) -BuildRequires: pkgconfig(libSimpleDbus) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libsystemd-journal) BuildRequires: pkgconfig(libsystemd-daemon) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 79ced75..9470754 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -31,7 +31,7 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-journal libsystemd-daemon - libcap-ng libLogger libSimpleDbus libConfig) + libcap-ng sqlite3) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) diff --git a/server/netdev.hpp b/server/netdev.hpp index b3c574d..eba9a01 100644 --- a/server/netdev.hpp +++ b/server/netdev.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 2a561ed..692ec4b 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -48,7 +48,7 @@ ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS}) FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-daemon - libsystemd-journal libcap-ng libLogger libSimpleDbus libConfig) + libsystemd-journal libcap-ng sqlite3) INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER} ${SOCKET_TEST_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) diff --git a/tests/unit_tests/socket_test_service/socket-test.cpp b/tests/unit_tests/socket_test_service/socket-test.cpp index 609bf87..2f163af 100644 --- a/tests/unit_tests/socket_test_service/socket-test.cpp +++ b/tests/unit_tests/socket_test_service/socket-test.cpp @@ -25,7 +25,7 @@ #include #include "socket-test.hpp" -#include +#include #include #include diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt index 7baf37f..7e7bfba 100644 --- a/zone-daemon/CMakeLists.txt +++ b/zone-daemon/CMakeLists.txt @@ -20,9 +20,9 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Zone Daemon...") FILE(GLOB project_SRCS *.cpp *.hpp) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/dbus/*.cpp ${COMMON_FOLDER}/dbus/*.hpp - ${COMMON_FOLDER}/log/*.cpp ${COMMON_FOLDER}/log/*.hpp - ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp +FILE(GLOB common_SRCS ${COMMON_FOLDER}/dbus/*.cpp ${COMMON_FOLDER}/dbus/*.hpp + ${COMMON_FOLDER}/logger/*.cpp ${COMMON_FOLDER}/logger/*.hpp + ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/*.cpp) ## Setup target ################################################################ @@ -33,8 +33,8 @@ ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) -PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal libcap-ng - libLogger libSimpleDbus libConfig) +PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal libcap-ng) + INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${ZONE_DAEMON_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) -- 2.7.4 From 3de62e50aefd71c74eeb1cf1872699c7a759e7e0 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 22 Apr 2015 14:43:51 +0200 Subject: [PATCH 13/16] Prevent from inheriting fd by zones [Bug] Opened ipc socket are inherited by lxc proces [Cause] fork and exec copies fds [Solution] Set FD_CLOEXEC on ipc fd [Verification] N/A Change-Id: I1d2af18bbbab3be5df292770537a398ee7b47b53 --- common/ipc/internals/socket.cpp | 22 ++++++++++++++++++---- common/utils/signal.cpp | 6 +++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/common/ipc/internals/socket.cpp b/common/ipc/internals/socket.cpp index a66456e..3cdbf7c 100644 --- a/common/ipc/internals/socket.cpp +++ b/common/ipc/internals/socket.cpp @@ -44,6 +44,16 @@ namespace ipc { namespace { const int MAX_QUEUE_LENGTH = 1000; + +void setFdOptions(int fd) +{ + // Prevent from inheriting fd by zones + if (-1 == ::fcntl(fd, F_SETFD, FD_CLOEXEC)) { + LOGE("Error in fcntl: " + std::string(strerror(errno))); + throw IPCException("Error in fcntl: " + std::string(strerror(errno))); + } +} + } Socket::Socket(int socketFD) @@ -81,8 +91,9 @@ std::shared_ptr Socket::accept() int sockfd = ::accept(mFD, nullptr, nullptr); if (sockfd == -1) { LOGE("Error in accept: " << std::string(strerror(errno))); - IPCException("Error in accept: " + std::string(strerror(errno))); + throw IPCException("Error in accept: " + std::string(strerror(errno))); } + setFdOptions(sockfd); return std::make_shared(sockfd); } @@ -109,7 +120,8 @@ int Socket::getSystemdSocket(const std::string& path) for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) { - if (0 < ::sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1, path.c_str(), 0)) { + if (0 < ::sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0)) { + setFdOptions(fd); return fd; } } @@ -130,6 +142,7 @@ int Socket::createZoneSocket(const std::string& path) LOGE("Error in socket: " + std::string(strerror(errno))); throw IPCException("Error in socket: " + std::string(strerror(errno))); } + setFdOptions(sockfd); ::sockaddr_un serverAddress; serverAddress.sun_family = AF_UNIX; @@ -144,7 +157,7 @@ int Socket::createZoneSocket(const std::string& path) std::string message = strerror(errno); utils::close(sockfd); LOGE("Error in bind: " << message); - IPCException("Error in bind: " + message); + throw IPCException("Error in bind: " + message); } if (-1 == ::listen(sockfd, @@ -152,7 +165,7 @@ int Socket::createZoneSocket(const std::string& path) std::string message = strerror(errno); utils::close(sockfd); LOGE("Error in listen: " << message); - IPCException("Error in listen: " + message); + throw IPCException("Error in listen: " + message); } return sockfd; @@ -180,6 +193,7 @@ Socket Socket::connectSocket(const std::string& path) LOGE("Error in socket: " + std::string(strerror(errno))); throw IPCException("Error in socket: " + std::string(strerror(errno))); } + setFdOptions(fd); sockaddr_un serverAddress; serverAddress.sun_family = AF_UNIX; diff --git a/common/utils/signal.cpp b/common/utils/signal.cpp index 39e7fca..fdb571c 100644 --- a/common/utils/signal.cpp +++ b/common/utils/signal.cpp @@ -39,18 +39,18 @@ void signalBlock(const int signalToBlock) ::sigset_t set; if (-1 == ::sigemptyset(&set)) { LOGE("Error in sigemptyset: " << std::string(strerror(errno))); - UtilsException("Error in sigemptyset: " + std::string(strerror(errno))); + throw UtilsException("Error in sigemptyset: " + std::string(strerror(errno))); } if (-1 ==::sigaddset(&set, signalToBlock)) { LOGE("Error in sigaddset: " << std::string(strerror(errno))); - UtilsException("Error in sigaddset: " + std::string(strerror(errno))); + throw UtilsException("Error in sigaddset: " + std::string(strerror(errno))); } int ret = ::pthread_sigmask(SIG_BLOCK, &set, nullptr /*&oldSet*/); if (ret != 0) { LOGE("Error in pthread_sigmask: " << std::to_string(ret)); - UtilsException("Error in pthread_sigmask: " + std::to_string(ret)); + throw UtilsException("Error in pthread_sigmask: " + std::to_string(ret)); } } -- 2.7.4 From 679bf6112a48d0b064f55a57e9053c0ef22edfc3 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 22 Apr 2015 18:48:07 +0200 Subject: [PATCH 14/16] Fix doxygen comment [Bux] Can't compile with clang 3.6 [Cause] Bad format of doxygen comment [Solution] N/A [Verification] Compile with clang. Change-Id: I7dc296317bf8c380faf4ea27321f58cb477d6f33 --- common/config/kvstore.hpp | 2 +- common/config/manager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/config/kvstore.hpp b/common/config/kvstore.hpp index 0717665..eaf568b 100644 --- a/common/config/kvstore.hpp +++ b/common/config/kvstore.hpp @@ -227,7 +227,7 @@ std::vector KVStore::getInternal(const std::string& key, std::vector*) * Uses '.' to connect the terms. * @param args components of the string * @tparam delim optional delimiter - * @tparam typename ... Args any type implementing str + * @tparam Args any type implementing str * @return string created from he args */ template diff --git a/common/config/manager.hpp b/common/config/manager.hpp index 0deb8d8..f3bac43 100644 --- a/common/config/manager.hpp +++ b/common/config/manager.hpp @@ -178,7 +178,7 @@ void saveToKVStore(const std::string& filename, const Config& config, const std: * Load the config from KVStore with defaults given in json * * @param kvfile path to the KVStore db - * @param jsonfile path to json file with defaults + * @param json path to json file with defaults * @param config visitable structure to save * @param kvConfigName name of the config inside the KVStore db */ -- 2.7.4 From f5632a71830b61ae81c2db084c9c44bf7b9f1864 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 22 Apr 2015 18:29:57 +0200 Subject: [PATCH 15/16] Prevent from server termination after SIGPIPE [Bug] Server killed after unexpected ipc client disconnect [Cause] Writing to a disconnected socket causes the SIGPIPE [Solution] Block signal [Verification] N/A Change-Id: I27d50be0279c87894acff74627b6385dff72b762 --- server/server.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/server.cpp b/server/server.cpp index 2271f08..f64ea03 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -33,6 +33,7 @@ #include "utils/glib-loop.hpp" #include "utils/environment.hpp" #include "utils/fs.hpp" +#include "utils/signal.hpp" #include #include @@ -101,6 +102,7 @@ void Server::run(bool asRoot) signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGUSR1, signalHandler); + utils::signalBlock(SIGPIPE); LOGI("Starting daemon..."); { -- 2.7.4 From e781e8693f2a9ddb8bce6bd1479b3e657dbbf648 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 21 Apr 2015 13:28:19 +0200 Subject: [PATCH 16/16] Rename: DispalyOff to SwitchToDefault, ZoneDbusState to ZoneConnectionState (switch to IPC #4) [Feature] Rename: DispalyOff to SwitchToDefault, ZoneDbusState to ZoneConnectionState (with related types and variables) [Cause] Switching from Dbus to IPC [Solution] N/A [Verification] Build, install, run tests Change-Id: Ibc331cd05d0f4b5d62400f449efd996268b91456 --- client/host-dbus-connection.cpp | 10 +- client/host-dbus-connection.hpp | 6 +- client/host-ipc-connection.cpp | 12 +- client/host-ipc-connection.hpp | 6 +- client/vasum-client-impl.cpp | 8 +- client/vasum-client.h | 4 +- common/api/messages.hpp | 4 +- server/configs/templates/default.conf | 2 +- server/host-dbus-connection.cpp | 16 +- server/host-dbus-connection.hpp | 10 +- server/host-dbus-definitions.hpp | 12 +- server/host-ipc-connection.cpp | 12 +- server/host-ipc-connection.hpp | 4 +- server/host-ipc-definitions.hpp | 4 +- server/zone-config.hpp | 4 +- server/zone-connection.cpp | 8 +- server/zone-connection.hpp | 8 +- server/zone.cpp | 40 ++-- server/zone.hpp | 16 +- server/zones-manager.cpp | 26 +-- server/zones-manager.hpp | 9 +- .../ut-client/templates/console-dbus.conf.in | 2 +- tests/unit_tests/client/ut-client.cpp | 28 +-- .../configs/ut-server/templates/default.conf | 2 +- .../configs/ut-zone-admin/templates/buggy.conf | 2 +- .../configs/ut-zone-admin/templates/missing.conf | 2 +- .../ut-zone-admin/templates/test-no-shutdown.conf | 2 +- .../configs/ut-zone-admin/templates/test.conf | 2 +- .../server/configs/ut-zone/templates/buggy.conf | 2 +- .../configs/ut-zone/templates/test-dbus.conf.in | 2 +- .../server/configs/ut-zone/templates/test.conf | 2 +- .../templates/console-dbus.conf.in | 2 +- .../ut-zones-manager/templates/console.conf | 2 +- tests/unit_tests/server/ut-zone-connection.cpp | 12 +- tests/unit_tests/server/ut-zones-manager.cpp | 219 +++++++++++---------- 35 files changed, 251 insertions(+), 251 deletions(-) diff --git a/client/host-dbus-connection.cpp b/client/host-dbus-connection.cpp index 7e511fe..1f375a0 100644 --- a/client/host-dbus-connection.cpp +++ b/client/host-dbus-connection.cpp @@ -170,16 +170,16 @@ void HostDbusConnection::callRevokeDevice(const vasum::api::RevokeDeviceIn& argI mConnection.call(vasum::api::host::METHOD_REVOKE_DEVICE, argIn); } -void HostDbusConnection::callGetZoneDbuses(vasum::api::Dbuses& argOut) +void HostDbusConnection::callGetZoneConnections(vasum::api::Connections& argOut) { - mConnection.call(vasum::api::host::METHOD_GET_ZONE_DBUSES, argOut); + mConnection.call(vasum::api::host::METHOD_GET_ZONE_CONNECTIONS, argOut); } HostDbusConnection::SubscriptionId -HostDbusConnection::subscribeZoneDbusState(const ZoneDbusStateCallback& callback) +HostDbusConnection::subscribeZoneConnectionState(const ZoneConnectionStateCallback& callback) { - return mConnection.signalSubscribe( - vasum::api::host::SIGNAL_ZONE_DBUS_STATE, callback); + return mConnection.signalSubscribe( + vasum::api::host::SIGNAL_ZONE_CONNECTION_STATE, callback); } void HostDbusConnection::unsubscribe(const SubscriptionId& id) diff --git a/client/host-dbus-connection.hpp b/client/host-dbus-connection.hpp index c7cebdb..8785fa0 100644 --- a/client/host-dbus-connection.hpp +++ b/client/host-dbus-connection.hpp @@ -40,7 +40,7 @@ namespace client { class HostDbusConnection { public: typedef unsigned int SubscriptionId; - typedef std::function ZoneDbusStateCallback; + typedef std::function ZoneConnectionStateCallback; HostDbusConnection(); @@ -71,8 +71,8 @@ public: void callUnlockZone(const vasum::api::ZoneId& argIn); void callGrantDevice(const vasum::api::GrantDeviceIn& argIn); void callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn); - void callGetZoneDbuses(vasum::api::Dbuses& argOut); - SubscriptionId subscribeZoneDbusState(const ZoneDbusStateCallback& callback); + void callGetZoneConnections(vasum::api::Connections& argOut); + SubscriptionId subscribeZoneConnectionState(const ZoneConnectionStateCallback& callback); void unsubscribe(const SubscriptionId& id); private: DbusConnection mConnection; diff --git a/client/host-ipc-connection.cpp b/client/host-ipc-connection.cpp index 6a22e6b..adb44eb 100644 --- a/client/host-ipc-connection.cpp +++ b/client/host-ipc-connection.cpp @@ -161,17 +161,17 @@ void HostIPCConnection::callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn mConnection.call(vasum::api::host::METHOD_REVOKE_DEVICE, argIn); } -void HostIPCConnection::callGetZoneDbuses(vasum::api::Dbuses& argOut) +void HostIPCConnection::callGetZoneConnections(vasum::api::Connections& argOut) { - mConnection.call(vasum::api::host::METHOD_GET_ZONE_DBUSES, argOut); + mConnection.call(vasum::api::host::METHOD_GET_ZONE_CONNECTIONS, argOut); } HostIPCConnection::SubscriptionId -HostIPCConnection::subscribeZoneDbusState(const ZoneDbusStateCallback& callback) +HostIPCConnection::subscribeZoneConnectionState(const ZoneConnectionStateCallback& callback) { - mConnection.subscribe( - vasum::api::host::SIGNAL_ZONE_DBUS_STATE, callback); - return vasum::api::host::SIGNAL_ZONE_DBUS_STATE; + mConnection.subscribe( + vasum::api::host::SIGNAL_ZONE_CONNECTION_STATE, callback); + return vasum::api::host::SIGNAL_ZONE_CONNECTION_STATE; } void HostIPCConnection::unsubscribe(const SubscriptionId& id) diff --git a/client/host-ipc-connection.hpp b/client/host-ipc-connection.hpp index 83313e1..216e976 100644 --- a/client/host-ipc-connection.hpp +++ b/client/host-ipc-connection.hpp @@ -38,7 +38,7 @@ namespace client { class HostIPCConnection { public: typedef unsigned int SubscriptionId; - typedef std::function ZoneDbusStateCallback; + typedef std::function ZoneConnectionStateCallback; void createSystem(); void callGetZoneIds(vasum::api::ZoneIds& argOut); @@ -66,8 +66,8 @@ public: void callUnlockZone(const vasum::api::ZoneId& argIn); void callGrantDevice(const vasum::api::GrantDeviceIn& argIn); void callRevokeDevice(const vasum::api::RevokeDeviceIn& argIn); - void callGetZoneDbuses(vasum::api::Dbuses& argOut); - SubscriptionId subscribeZoneDbusState(const ZoneDbusStateCallback& callback); + void callGetZoneConnections(vasum::api::Connections& argOut); + SubscriptionId subscribeZoneConnectionState(const ZoneConnectionStateCallback& callback); void unsubscribe(const SubscriptionId& id); private: diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 2d85fb0..49b5846 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -258,8 +258,8 @@ VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* keys, VsmArrayString* valu assert(values); return coverException([&] { - api::Dbuses dbuses; - mHostClient.callGetZoneDbuses(dbuses); + api::Connections dbuses; + mHostClient.callGetZoneConnections(dbuses); convert(dbuses, *keys, *values); }); } @@ -397,7 +397,7 @@ VsmStatus Client::vsm_add_state_callback(VsmZoneDbusStateCallback zoneDbusStateC assert(zoneDbusStateCallback); return coverException([&] { - auto onSigal = [=](const api::DbusState& dbus) + auto onSigal = [=](const api::ConnectionState& dbus) { zoneDbusStateCallback(dbus.first.c_str(), dbus.second.c_str(), @@ -405,7 +405,7 @@ VsmStatus Client::vsm_add_state_callback(VsmZoneDbusStateCallback zoneDbusStateC }; VsmSubscriptionId id; - id = mHostClient.subscribeZoneDbusState(onSigal); + id = mHostClient.subscribeZoneConnectionState(onSigal); if (subscriptionId) { *subscriptionId = id; } diff --git a/client/vasum-client.h b/client/vasum-client.h index c252b32..50ed162 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -293,11 +293,11 @@ void vsm_netdev_free(VsmNetdev netdev); * Zone's D-Bus state change callback function signature. * * @param[in] zoneId affected zone id - * @param[in] dbusAddress new D-Bus address + * @param[in] address new D-Bus address * @param data custom user's data pointer passed to vsm_add_state_callback() function */ typedef void (*VsmZoneDbusStateCallback)(const char* zoneId, - const char* dbusAddress, + const char* address, void* data); /** diff --git a/common/api/messages.hpp b/common/api/messages.hpp index de606c0..ca4cab2 100644 --- a/common/api/messages.hpp +++ b/common/api/messages.hpp @@ -84,13 +84,13 @@ typedef api::StringPair RemoveDeclarationIn; typedef api::StringPair CreateZoneIn; typedef api::StringPair RevokeDeviceIn; typedef api::StringPair DestroyNetDevIn; -typedef api::StringPair DbusState; +typedef api::StringPair ConnectionState; typedef api::StringPair NotifActiveZoneIn; typedef api::StringPair FileMoveRequestIn; typedef api::VectorOfStrings ZoneIds; typedef api::VectorOfStrings Declarations; typedef api::VectorOfStrings NetDevList; -typedef api::VectorOfStringPairs Dbuses; +typedef api::VectorOfStringPairs Connections; typedef api::VectorOfStringPairs GetNetDevAttrs; struct ZoneInfoOut { diff --git a/server/configs/templates/default.conf b/server/configs/templates/default.conf index 697be47..3a99d20 100644 --- a/server/configs/templates/default.conf +++ b/server/configs/templates/default.conf @@ -10,7 +10,7 @@ "vt" : 0, "shutdownTimeout" : 10, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "runMountPoint" : "~NAME~/run", "provisions" : [], "permittedToSend" : [ "/tmp/.*" ], diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index b3eb19d..76f5bb8 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -112,9 +112,9 @@ void HostDbusConnection::setProxyCallCallback(const ProxyCallCallback& callback) mProxyCallCallback = callback; } -void HostDbusConnection::setGetZoneDbusesCallback(const GetZoneDbusesCallback& callback) +void HostDbusConnection::setGetZoneConnectionsCallback(const GetZoneConnectionsCallback& callback) { - mGetZoneDbusesCallback = callback; + mGetZoneConnectionsCallback = callback; } void HostDbusConnection::setGetZoneIdsCallback(const GetZoneIdsCallback& callback) @@ -264,10 +264,10 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, return; } - if (methodName == api::host::METHOD_GET_ZONE_DBUSES) { - if (mGetZoneDbusesCallback) { - auto rb = std::make_shared>(result); - mGetZoneDbusesCallback(rb); + if (methodName == api::host::METHOD_GET_ZONE_CONNECTIONS) { + if (mGetZoneConnectionsCallback) { + auto rb = std::make_shared>(result); + mGetZoneConnectionsCallback(rb); } return; } @@ -569,12 +569,12 @@ void HostDbusConnection::proxyCallAsync(const std::string& busName, callback); } -void HostDbusConnection::signalZoneDbusState(const api::DbusState& state) +void HostDbusConnection::signalZoneConnectionState(const api::ConnectionState& state) { GVariant* parameters = g_variant_new("(ss)", state.first.c_str(), state.second.c_str()); mDbusConnection->emitSignal(api::host::OBJECT_PATH, api::host::INTERFACE, - api::host::SIGNAL_ZONE_DBUS_STATE, + api::host::SIGNAL_ZONE_CONNECTION_STATE, parameters); } diff --git a/server/host-dbus-connection.hpp b/server/host-dbus-connection.hpp index 980b5e9..455437d 100644 --- a/server/host-dbus-connection.hpp +++ b/server/host-dbus-connection.hpp @@ -57,7 +57,7 @@ public: dbus::MethodResultBuilder::Pointer result )> ProxyCallCallback; typedef std::function GetZoneDbusesCallback; + )> GetZoneConnectionsCallback; typedef std::function GetZoneIdsCallback; typedef std::function" " " - " " - " " + " " + " " " " " " " " @@ -196,9 +196,9 @@ const std::string DEFINITION = " " " " " " - " " + " " " " - " " + " " " " " " ""; diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index bb8d081..817e62f 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -52,11 +52,11 @@ HostIPCConnection::~HostIPCConnection() { } -void HostIPCConnection::setGetZoneDbusesCallback(const Callback::type& callback) +void HostIPCConnection::setGetZoneConnectionsCallback(const Callback::type& callback) { - typedef Callback Callback; + typedef Callback Callback; mService->setMethodHandler( - api::host::METHOD_GET_ZONE_DBUSES, + api::host::METHOD_GET_ZONE_CONNECTIONS, Callback::getCallbackWrapper(callback)); } @@ -263,10 +263,10 @@ void HostIPCConnection::setRevokeDeviceCallback(const Callbacksignal(api::host::SIGNAL_ZONE_DBUS_STATE, - std::make_shared(dbusState)); + mService->signal(api::host::SIGNAL_ZONE_CONNECTION_STATE, + std::make_shared(connectionState)); } } // namespace vasum diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index e8c1c8d..61c8f4a 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -81,7 +81,7 @@ public: HostIPCConnection(); ~HostIPCConnection(); - void setGetZoneDbusesCallback(const Callback::type& callback); + void setGetZoneConnectionsCallback(const Callback::type& callback); void setGetZoneIdsCallback(const Callback::type& callback); void setGetActiveZoneIdCallback(const Callback::type& callback); void setGetZoneInfoCallback(const Callback::type& callback); @@ -107,7 +107,7 @@ public: void setUnlockZoneCallback(const Callback::type& callback); void setGrantDeviceCallback(const Callback::type& callback); void setRevokeDeviceCallback(const Callback::type& callback); - void signalZoneDbusState(const api::DbusState& dbusState); + void signalZoneConnectionState(const api::ConnectionState& connectionState); private: epoll::ThreadDispatcher mDispatcher; diff --git a/server/host-ipc-definitions.hpp b/server/host-ipc-definitions.hpp index 4cd06e7..b1fca09 100644 --- a/server/host-ipc-definitions.hpp +++ b/server/host-ipc-definitions.hpp @@ -31,7 +31,7 @@ namespace vasum { namespace api { namespace host { -const vasum::ipc::MethodID METHOD_GET_ZONE_DBUSES = 1; +const vasum::ipc::MethodID METHOD_GET_ZONE_CONNECTIONS = 1; const vasum::ipc::MethodID METHOD_GET_ZONE_ID_LIST = 2; const vasum::ipc::MethodID METHOD_GET_ACTIVE_ZONE_ID = 3; const vasum::ipc::MethodID METHOD_GET_ZONE_INFO = 4; @@ -58,7 +58,7 @@ const vasum::ipc::MethodID METHOD_UNLOCK_ZONE = 24; const vasum::ipc::MethodID METHOD_GRANT_DEVICE = 25; const vasum::ipc::MethodID METHOD_REVOKE_DEVICE = 26; -const vasum::ipc::MethodID SIGNAL_ZONE_DBUS_STATE = 27; +const vasum::ipc::MethodID SIGNAL_ZONE_CONNECTION_STATE = 27; } // namespace host } // namespace api diff --git a/server/zone-config.hpp b/server/zone-config.hpp index 8d92800..67b5f93 100644 --- a/server/zone-config.hpp +++ b/server/zone-config.hpp @@ -63,7 +63,7 @@ struct ZoneConfig { * Specify, if D-Bus communication with the zone will be enabled. * Setting this value to "false" will make the zone API not work inside the zone. */ - bool enableDbusIntegration; + bool enableZoneConnection; /** * Zone's CFS quota in us when it's in the foreground @@ -106,7 +106,7 @@ struct ZoneConfig { initWithArgs, privilege, // TODO not needed? switchToDefaultAfterTimeout, // TODO move to dynamic and add an API to change - enableDbusIntegration, + enableZoneConnection, cpuQuotaForeground, cpuQuotaBackground, permittedToSend, // TODO move to dynamic and add an API to change diff --git a/server/zone-connection.cpp b/server/zone-connection.cpp index a86886c..56aa547 100644 --- a/server/zone-connection.cpp +++ b/server/zone-connection.cpp @@ -137,9 +137,9 @@ void ZoneConnection::setNotifyActiveZoneCallback( mNotifyActiveZoneCallback = callback; } -void ZoneConnection::setDisplayOffCallback(const DisplayOffCallback& callback) +void ZoneConnection::setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback) { - mDisplayOffCallback = callback; + mSwitchToDefaultCallback = callback; } void ZoneConnection::setFileMoveCallback( @@ -223,8 +223,8 @@ void ZoneConnection::onSignalReceived(const std::string& senderBusName, if (objectPath == fake_power_manager_api::OBJECT_PATH && interface == fake_power_manager_api::INTERFACE) { //power-manager sent us a signal, check it - if (signalName == fake_power_manager_api::SIGNAL_DISPLAY_OFF && mDisplayOffCallback) { - mDisplayOffCallback(); + if (signalName == fake_power_manager_api::SIGNAL_DISPLAY_OFF && mSwitchToDefaultCallback) { + mSwitchToDefaultCallback(); } } } diff --git a/server/zone-connection.hpp b/server/zone-connection.hpp index 8f025b0..441f645 100644 --- a/server/zone-connection.hpp +++ b/server/zone-connection.hpp @@ -39,7 +39,7 @@ class ZoneConnection { public: typedef std::function OnNameLostCallback; - typedef std::function DisplayOffCallback; + typedef std::function SwitchToDefaultCallback; ZoneConnection(const std::string& address, const OnNameLostCallback& callback); ~ZoneConnection(); @@ -71,9 +71,9 @@ public: void setNotifyActiveZoneCallback(const NotifyActiveZoneCallback& callback); /** - * Register callback to handle turning off the display + * Register switch to default request callback */ - void setDisplayOffCallback(const DisplayOffCallback& callback); + void setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback); /* * Register file move request callback @@ -110,7 +110,7 @@ private: bool mNameLost; OnNameLostCallback mOnNameLostCallback; NotifyActiveZoneCallback mNotifyActiveZoneCallback; - DisplayOffCallback mDisplayOffCallback; + SwitchToDefaultCallback mSwitchToDefaultCallback; FileMoveCallback mFileMoveCallback; ProxyCallCallback mProxyCallCallback; diff --git a/server/zone.cpp b/server/zone.cpp index e26da52..2e47f25 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -164,12 +164,12 @@ void Zone::start() Lock lock(mReconnectMutex); updateRequestedState(STATE_RUNNING); mProvision->start(); - if (mConfig.enableDbusIntegration) { + if (mConfig.enableZoneConnection) { mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint)); } mAdmin->start(); - if (mConfig.enableDbusIntegration) { + if (mConfig.enableZoneConnection) { // Increase cpu quota before connect, otherwise it'd take ages. goForeground(); connect(); @@ -196,14 +196,14 @@ void Zone::stop(bool saveState) void Zone::connect() { // assume called under reconnect lock - mDbusAddress = mConnectionTransport->acquireAddress(); - mConnection.reset(new ZoneConnection(mDbusAddress, - std::bind(&Zone::onNameLostCallback, this))); + mConnectionAddress = mConnectionTransport->acquireAddress(); + mConnection.reset(new ZoneConnection(mConnectionAddress, + std::bind(&Zone::onNameLostCallback, this))); if (mNotifyCallback) { mConnection->setNotifyActiveZoneCallback(mNotifyCallback); } - if (mDisplayOffCallback) { - mConnection->setDisplayOffCallback(mDisplayOffCallback); + if (mSwitchToDefaultCallback) { + mConnection->setSwitchToDefaultCallback(mSwitchToDefaultCallback); } if (mFileMoveCallback) { mConnection->setFileMoveCallback(mFileMoveCallback); @@ -211,8 +211,8 @@ void Zone::connect() if (mProxyCallCallback) { mConnection->setProxyCallCallback(mProxyCallCallback); } - if (mDbusStateChangedCallback) { - mDbusStateChangedCallback(mDbusAddress); + if (mConnectionStateChangedCallback) { + mConnectionStateChangedCallback(mConnectionAddress); } } @@ -221,18 +221,18 @@ void Zone::disconnect() // assume called under reconnect lock if (mConnection) { mConnection.reset(); - mDbusAddress.clear(); - if (mDbusStateChangedCallback) { - // notify about invalid dbusAddress for this zone - mDbusStateChangedCallback(std::string()); + mConnectionAddress.clear(); + if (mConnectionStateChangedCallback) { + // notify about invalid address for this zone + mConnectionStateChangedCallback(std::string()); } } } -std::string Zone::getDbusAddress() const +std::string Zone::getConnectionAddress() const { Lock lock(mReconnectMutex); - return mDbusAddress; + return mConnectionAddress; } int Zone::getVT() const @@ -407,13 +407,13 @@ void Zone::sendNotification(const std::string& zone, } } -void Zone::setDisplayOffCallback(const DisplayOffCallback& callback) +void Zone::setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback) { Lock lock(mReconnectMutex); - mDisplayOffCallback = callback; + mSwitchToDefaultCallback = callback; if (mConnection) { - mConnection->setDisplayOffCallback(callback); + mConnection->setSwitchToDefaultCallback(callback); } } @@ -437,9 +437,9 @@ void Zone::setProxyCallCallback(const ProxyCallCallback& callback) } } -void Zone::setDbusStateChangedCallback(const DbusStateChangedCallback& callback) +void Zone::setConnectionStateChangedCallback(const ConnectionStateChangedCallback& callback) { - mDbusStateChangedCallback = callback; + mConnectionStateChangedCallback = callback; } void Zone::proxyCallAsync(const std::string& busName, diff --git a/server/zone.hpp b/server/zone.hpp index 687077f..e7e929a 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -66,11 +66,11 @@ public: ~Zone(); typedef ZoneConnection::NotifyActiveZoneCallback NotifyActiveZoneCallback; - typedef ZoneConnection::DisplayOffCallback DisplayOffCallback; + typedef ZoneConnection::SwitchToDefaultCallback SwitchToDefaultCallback; typedef ZoneConnection::FileMoveCallback FileMoveCallback; typedef ZoneConnection::ProxyCallCallback ProxyCallCallback; - typedef std::function DbusStateChangedCallback; + typedef std::function ConnectionStateChangedCallback; typedef std::function StartAsyncResultCallback; /** @@ -189,7 +189,7 @@ public: /** * Register callback used when switching to default zone. */ - void setDisplayOffCallback(const DisplayOffCallback& callback); + void setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback); /** * Register proxy call callback @@ -215,7 +215,7 @@ public: /** * Register dbus state changed callback */ - void setDbusStateChangedCallback(const DbusStateChangedCallback& callback); + void setConnectionStateChangedCallback(const ConnectionStateChangedCallback& callback); /** * Make a proxy call @@ -230,7 +230,7 @@ public: /** * Get a dbus address */ - std::string getDbusAddress() const; + std::string getConnectionAddress() const; /** * Get id of VT @@ -328,11 +328,11 @@ private: std::unique_ptr mProvision; mutable std::recursive_mutex mReconnectMutex; NotifyActiveZoneCallback mNotifyCallback; - DisplayOffCallback mDisplayOffCallback; + SwitchToDefaultCallback mSwitchToDefaultCallback; FileMoveCallback mFileMoveCallback; ProxyCallCallback mProxyCallCallback; - DbusStateChangedCallback mDbusStateChangedCallback; - std::string mDbusAddress; + ConnectionStateChangedCallback mConnectionStateChangedCallback; + std::string mConnectionAddress; std::string mRunMountPoint; std::string mRootPath; std::string mDbPath; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 11589bd..1b6edf3 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -132,8 +132,8 @@ ZonesManager::ZonesManager(const std::string& configPath) this, HOST_ID, _1, _2, _3, _4, _5, _6, _7)); #endif - mHostConnection.setGetZoneDbusesCallback(bind(&ZonesManager::handleGetZoneDbusesCall, - this, _1)); + mHostConnection.setGetZoneConnectionsCallback(bind(&ZonesManager::handleGetZoneConnectionsCall, + this, _1)); mHostConnection.setGetZoneIdsCallback(bind(&ZonesManager::handleGetZoneIdsCall, this, _1)); @@ -319,7 +319,7 @@ void ZonesManager::insertZone(const std::string& zoneId, const std::string& zone zone->setNotifyActiveZoneCallback(bind(&ZonesManager::handleNotifyActiveZoneCall, this, zoneId, _1, _2, _3)); - zone->setDisplayOffCallback(bind(&ZonesManager::handleDisplayOffCall, + zone->setSwitchToDefaultCallback(bind(&ZonesManager::handleSwitchToDefaultCall, this, zoneId)); zone->setFileMoveCallback(bind(&ZonesManager::handleFileMoveCall, @@ -328,8 +328,8 @@ void ZonesManager::insertZone(const std::string& zoneId, const std::string& zone zone->setProxyCallCallback(bind(&ZonesManager::handleProxyCall, this, zoneId, _1, _2, _3, _4, _5, _6, _7)); - zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged, - this, zoneId, _1)); + zone->setConnectionStateChangedCallback(bind(&ZonesManager::handleConnectionStateChanged, + this, zoneId, _1)); mZones.push_back(std::move(zone)); @@ -578,7 +578,7 @@ void ZonesManager::handleNotifyActiveZoneCall(const std::string& caller, } } -void ZonesManager::handleDisplayOffCall(const std::string& /*caller*/) +void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/) { // get config of currently set zone and switch if switchToDefaultAfterTimeout is true Lock lock(mMutex); @@ -750,21 +750,21 @@ void ZonesManager::handleProxyCall(const std::string& caller, asyncResultCallback); } -void ZonesManager::handleGetZoneDbusesCall(api::MethodResultBuilder::Pointer result) +void ZonesManager::handleGetZoneConnectionsCall(api::MethodResultBuilder::Pointer result) { Lock lock(mMutex); - auto dbuses = std::make_shared(); + auto connections = std::make_shared(); for (auto& zone : mZones) { - dbuses->values.push_back({zone->getId(), zone->getDbusAddress()}); + connections->values.push_back({zone->getId(), zone->getConnectionAddress()}); } - result->set(dbuses); + result->set(connections); } -void ZonesManager::handleDbusStateChanged(const std::string& zoneId , - const std::string& dbusAddress) +void ZonesManager::handleConnectionStateChanged(const std::string& zoneId , + const std::string& address) { - mHostConnection.signalZoneDbusState({zoneId, dbusAddress}); + mHostConnection.signalZoneConnectionState({zoneId, address}); } void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result) diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 84285f3..31c90cd 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -160,7 +160,7 @@ private: const std::string& appliaction, const std::string& message, api::MethodResultBuilder::Pointer result); - void handleDisplayOffCall(const std::string& caller); + void handleSwitchToDefaultCall(const std::string& caller); void handleFileMoveCall(const std::string& srcZoneId, const std::string& dstZoneId, const std::string& path, @@ -173,10 +173,9 @@ private: const std::string& targetMethod, GVariant* parameters, dbus::MethodResultBuilder::Pointer result); - void handleGetZoneDbusesCall(api::MethodResultBuilder::Pointer result); - - void handleDbusStateChanged(const std::string& zoneId, - const std::string& dbusAddress); + void handleGetZoneConnectionsCall(api::MethodResultBuilder::Pointer result); + void handleConnectionStateChanged(const std::string& zoneId, + const std::string& address); // Host's handlers -------------------------------------------------------- void handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result); diff --git a/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in index 7df03e4..3481c09 100644 --- a/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in +++ b/tests/unit_tests/client/configs/ut-client/templates/console-dbus.conf.in @@ -7,7 +7,7 @@ "privilege" : 20, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, + "enableZoneConnection" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 40372f4..d53238f 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -88,7 +88,7 @@ struct Fixture { }; const int EVENT_TIMEOUT = 5000; ///< ms -const std::map EXPECTED_DBUSES_STARTED = { +const std::map EXPECTED_CONNECTIONS = { { "zone1", "unix:path=/tmp/ut-run/zone1/dbus/system_bus_socket" @@ -157,12 +157,12 @@ BOOST_AUTO_TEST_CASE(NotRunningServer) VsmClient client = vsm_client_create(); VsmStatus status = vsm_connect_custom(client, - EXPECTED_DBUSES_STARTED.begin()->second.c_str()); + EXPECTED_CONNECTIONS.begin()->second.c_str()); BOOST_CHECK_EQUAL(VSMCLIENT_IO_ERROR, status); vsm_client_free(client); } -BOOST_AUTO_TEST_CASE(GetZoneDbuses) +BOOST_AUTO_TEST_CASE(GetZoneConnections) { VsmClient client = vsm_client_create(); VsmStatus status = vsm_connect(client); @@ -172,14 +172,14 @@ BOOST_AUTO_TEST_CASE(GetZoneDbuses) //TODO: Clean up if BOOST_REQUIRE_EQUAL fail (remove client). Same in other client tests. BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); - BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_DBUSES_STARTED.size() + 1u), - EXPECTED_DBUSES_STARTED.size()); - BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1u), - EXPECTED_DBUSES_STARTED.size()); + BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_CONNECTIONS.size() + 1u), + EXPECTED_CONNECTIONS.size()); + BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_CONNECTIONS.size() + 1u), + EXPECTED_CONNECTIONS.size()); std::map zones; convertDictToMap(keys, values, zones); - BOOST_CHECK(zones == EXPECTED_DBUSES_STARTED); + BOOST_CHECK(zones == EXPECTED_CONNECTIONS); vsm_array_string_free(keys); vsm_array_string_free(values); vsm_client_free(client); @@ -193,14 +193,14 @@ BOOST_AUTO_TEST_CASE(GetZoneIds) VsmArrayString values; status = vsm_get_zone_ids(client, &values); BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); - BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1u), - EXPECTED_DBUSES_STARTED.size()); + BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_CONNECTIONS.size() + 1u), + EXPECTED_CONNECTIONS.size()); std::set zones; convertArrayToSet(values, zones); for (const auto& zone : zones) { - BOOST_CHECK(EXPECTED_DBUSES_STARTED.find(zone) != EXPECTED_DBUSES_STARTED.cend()); + BOOST_CHECK(EXPECTED_CONNECTIONS.find(zone) != EXPECTED_CONNECTIONS.cend()); } vsm_array_string_free(values); vsm_client_free(client); @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(FileMoveRequest) const std::string secondZone = "fake_zone"; VsmClient client = vsm_client_create(); - VsmStatus status = vsm_connect_custom(client, EXPECTED_DBUSES_STARTED.begin()->second.c_str()); + VsmStatus status = vsm_connect_custom(client, EXPECTED_CONNECTIONS.begin()->second.c_str()); BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); status = vsm_file_move_request(client, secondZone.c_str(), path.c_str()); BOOST_REQUIRE_EQUAL(VSMCLIENT_CUSTOM_ERROR, status); @@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(Notification) CallbackData callbackData; std::map clients; - for (const auto& it : EXPECTED_DBUSES_STARTED) { + for (const auto& it : EXPECTED_CONNECTIONS) { VsmClient client = vsm_client_create(); VsmStatus status = vsm_connect_custom(client, it.second.c_str()); BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); @@ -398,7 +398,7 @@ BOOST_AUTO_TEST_CASE(GetZoneIdByPidTestMultiple) BOOST_CHECK(ids.count("host") == 1); - for (const auto& dbus : EXPECTED_DBUSES_STARTED) { + for (const auto& dbus : EXPECTED_CONNECTIONS) { BOOST_CHECK(ids.count(dbus.first) == 1); } } diff --git a/tests/unit_tests/server/configs/ut-server/templates/default.conf b/tests/unit_tests/server/configs/ut-server/templates/default.conf index b637d72..d07ecc6 100644 --- a/tests/unit_tests/server/configs/ut-server/templates/default.conf +++ b/tests/unit_tests/server/configs/ut-server/templates/default.conf @@ -7,7 +7,7 @@ "privilege" : 20, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf index c40ab33..c3b07fe 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/buggy.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf index 99e893d..7e20d62 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/missing.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf index 363c7df..4aa7bd2 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test-no-shutdown.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf index df787df..5083c0e 100644 --- a/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf +++ b/tests/unit_tests/server/configs/ut-zone-admin/templates/test.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf index 91a9f7f..1e71ece 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/buggy.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in index 7d71f2d..da02e3b 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zone/templates/test-dbus.conf.in @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, + "enableZoneConnection" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zone/templates/test.conf b/tests/unit_tests/server/configs/ut-zone/templates/test.conf index a58f932..7827fe3 100644 --- a/tests/unit_tests/server/configs/ut-zone/templates/test.conf +++ b/tests/unit_tests/server/configs/ut-zone/templates/test.conf @@ -7,7 +7,7 @@ "privilege" : 10, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in index 7df03e4..3481c09 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console-dbus.conf.in @@ -7,7 +7,7 @@ "privilege" : 20, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : true, + "enableZoneConnection" : true, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf index 5d5509b..d9f69ec 100644 --- a/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf +++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/console.conf @@ -7,7 +7,7 @@ "privilege" : 20, "vt" : -1, "switchToDefaultAfterTimeout" : true, - "enableDbusIntegration" : false, + "enableZoneConnection" : false, "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "shutdownTimeout" : 10, diff --git a/tests/unit_tests/server/ut-zone-connection.cpp b/tests/unit_tests/server/ut-zone-connection.cpp index 5f2c63b..c374c81 100644 --- a/tests/unit_tests/server/ut-zone-connection.cpp +++ b/tests/unit_tests/server/ut-zone-connection.cpp @@ -196,18 +196,18 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApi) BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT)); } -BOOST_AUTO_TEST_CASE(SignalDisplayOffApi) +BOOST_AUTO_TEST_CASE(SignalSwitchToDefaultApi) { - Latch displayOffCalled; + Latch switchToDefaultCalled; ZoneConnection connection(acquireAddress(), nullptr); DbusConnection::Pointer client = DbusConnection::create(acquireAddress()); auto callback = [&]() { - displayOffCalled.set(); + switchToDefaultCalled.set(); }; - connection.setDisplayOffCallback(callback); + connection.setSwitchToDefaultCallback(callback); client->emitSignal(fake_power_manager_api::OBJECT_PATH, fake_power_manager_api::INTERFACE, @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(SignalDisplayOffApi) nullptr); // timeout should occur, since no name is set to client - BOOST_CHECK(!displayOffCalled.wait(EVENT_TIMEOUT)); + BOOST_CHECK(!switchToDefaultCalled.wait(EVENT_TIMEOUT)); DbusNameSetter setter; @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(SignalDisplayOffApi) nullptr); // now signal should be delivered correctly - BOOST_CHECK(displayOffCalled.wait(EVENT_TIMEOUT)); + BOOST_CHECK(switchToDefaultCalled.wait(EVENT_TIMEOUT)); } diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 12a3dbe..5a9693f 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -82,7 +82,7 @@ const std::string FILE_CONTENT = "File content\n" const std::string NON_EXISTANT_ZONE_ID = "NON_EXISTANT_ZONE_ID"; const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf const std::string SIMPLE_TEMPLATE = "console"; -const std::string DBUS_TEMPLATE = "console-dbus"; +const std::string ZONE_ACCESS_TEMPLATE = "console-dbus"; #ifdef DBUS_CONNECTION /** @@ -110,9 +110,9 @@ public: )> TestApiMethodCallback; typedef std::function VoidResultCallback; typedef std::function SignalCallback; + const std::string& address)> SignalCallback; - typedef std::map Dbuses; + typedef std::map Connections; DbusAccessory() : mId(0), @@ -168,7 +168,7 @@ public: mClient->signalSubscribe(callback, isHost() ? api::host::BUS_NAME : api::zone::BUS_NAME); } - void subscribeZoneDbusState(const SignalCallback& callback) { + void subscribeZoneConnectionState(const SignalCallback& callback) { assert(isHost()); auto onSignal = [callback] (const std::string& /*senderBusName*/, const std::string& objectPath, @@ -177,12 +177,12 @@ public: GVariant* parameters) { if (objectPath == api::host::OBJECT_PATH && interface == api::host::INTERFACE && - signalName == api::host::SIGNAL_ZONE_DBUS_STATE) { + signalName == api::host::SIGNAL_ZONE_CONNECTION_STATE) { const gchar* zoneId = NULL; - const gchar* dbusAddress = NULL; - g_variant_get(parameters, "(&s&s)", &zoneId, &dbusAddress); - callback(zoneId, dbusAddress); + const gchar* address = NULL; + g_variant_get(parameters, "(&s&s)", &zoneId, &address); + callback(zoneId, address); } }; mClient->signalSubscribe(onSignal, api::host::BUS_NAME); @@ -285,14 +285,14 @@ public: return GVariantPtr(unpackedResult, g_variant_unref); } - Dbuses callMethodGetZoneDbuses() + Connections callMethodGetZoneConnections() { assert(isHost()); - Dbuses dbuses; + Connections connections; GVariantPtr result = mClient->callMethod(api::host::BUS_NAME, api::host::OBJECT_PATH, api::host::INTERFACE, - api::host::METHOD_GET_ZONE_DBUSES, + api::host::METHOD_GET_ZONE_CONNECTIONS, NULL, "(a(ss))"); GVariant* array = NULL; @@ -301,11 +301,11 @@ public: size_t count = g_variant_n_children(array); for (size_t n = 0; n < count; ++n) { const char* zoneId = NULL; - const char* dbusAddress = NULL; - g_variant_get_child(array, n, "(&s&s)", &zoneId, &dbusAddress); - dbuses.insert(Dbuses::value_type(zoneId, dbusAddress)); + const char* address = NULL; + g_variant_get_child(array, n, "(&s&s)", &zoneId, &address); + connections.insert(Connections::value_type(zoneId, address)); } - return dbuses; + return connections; } std::vector callMethodGetZoneIds() @@ -502,9 +502,9 @@ public: )> TestApiMethodCallback; typedef std::function VoidResultCallback; typedef std::function SignalCallback; + const std::string& address)> SignalCallback; - typedef std::map Dbuses; + typedef std::map Connections; HostIPCAccessory() : mClient(mDispatcher.getPoll(), HOST_IPC_SOCKET) @@ -512,23 +512,24 @@ public: mClient.start(); } - void subscribeZoneDbusState(const SignalCallback& callback) + void subscribeZoneConnectionState(const SignalCallback& callback) { - auto callbackWrapper = [callback] (const ipc::PeerID, std::shared_ptr& data) { + auto callbackWrapper = [callback] (const ipc::PeerID, std::shared_ptr& data) { callback(data->first, data->second); }; - mClient.setSignalHandler(api::host::SIGNAL_ZONE_DBUS_STATE, callbackWrapper); + mClient.setSignalHandler(api::host::SIGNAL_ZONE_CONNECTION_STATE, + callbackWrapper); } - Dbuses callMethodGetZoneDbuses() + Connections callMethodGetZoneConnections() { - const auto out = mClient.callSync(api::host::METHOD_GET_ZONE_DBUSES, - std::make_shared()); - Dbuses dbuses; + const auto out = mClient.callSync(api::host::METHOD_GET_ZONE_CONNECTIONS, + std::make_shared()); + Connections connections; for (const auto& dbus : out->values) { - dbuses.insert(Dbuses::value_type(dbus.first, dbus.second)); + connections.insert(Connections::value_type(dbus.first, dbus.second)); } - return dbuses; + return connections; } std::vector callMethodGetZoneIds() @@ -629,7 +630,7 @@ public: MethodResultBuilder::Pointer result )> TestApiMethodCallback; - typedef std::map Dbuses; + typedef std::map Connections; ZoneDbusAccessory(int id) : mId(id), @@ -891,17 +892,17 @@ BOOST_AUTO_TEST_CASE(Focus) BOOST_AUTO_TEST_CASE(NotifyActiveZone) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); Latch signalReceivedLatch; std::map> signalReceivedSourcesMap; - std::map> dbuses; + std::map> connections; for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); + connections[i] = std::unique_ptr(new ZoneAccessory(i)); } auto handler = [](Latch& latch, @@ -930,16 +931,16 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZone) using namespace std::placeholders; for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - dbuses[i]->signalSubscribe(std::bind(handler, + connections[i]->signalSubscribe(std::bind(handler, std::ref(signalReceivedLatch), std::ref(signalReceivedSourcesMap[i]), _1, _2, _3, _4, _5)); } - for (auto& dbus : dbuses) { + for (auto& dbus : connections) { dbus.second->callMethodNotify(); } - BOOST_REQUIRE(signalReceivedLatch.waitForN(dbuses.size() - 1u, EVENT_TIMEOUT)); + BOOST_REQUIRE(signalReceivedLatch.waitForN(connections.size() - 1u, EVENT_TIMEOUT)); BOOST_REQUIRE(signalReceivedLatch.empty()); //check if there are no signals that was received more than once @@ -949,21 +950,21 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZone) source), 1); } //check if all signals was received by active zone - BOOST_CHECK_EQUAL(signalReceivedSourcesMap[1].size(), dbuses.size() - 1); + BOOST_CHECK_EQUAL(signalReceivedSourcesMap[1].size(), connections.size() - 1); //check if no signals was received by inactive zone - for (size_t i = 2; i <= dbuses.size(); ++i) { + for (size_t i = 2; i <= connections.size(); ++i) { BOOST_CHECK(signalReceivedSourcesMap[i].empty()); } - dbuses.clear(); + connections.clear(); } -BOOST_AUTO_TEST_CASE(DisplayOff) +BOOST_AUTO_TEST_CASE(SwitchToDefault) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); std::vector> clients; @@ -998,9 +999,9 @@ BOOST_AUTO_TEST_CASE(DisplayOff) BOOST_AUTO_TEST_CASE(MoveFile) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); Latch notificationLatch; @@ -1008,9 +1009,9 @@ BOOST_AUTO_TEST_CASE(MoveFile) std::string notificationPath; std::string notificationRetcode; - std::map> dbuses; + std::map> connections; for (int i = 1; i <= 2; ++i) { - dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); + connections[i] = std::unique_ptr(new ZoneAccessory(i)); } auto handler = [&](const std::string& /*senderBusName*/, @@ -1037,7 +1038,7 @@ BOOST_AUTO_TEST_CASE(MoveFile) }; // subscribe the second (destination) zone for notifications - dbuses.at(2)->signalSubscribe(handler); + connections.at(2)->signalSubscribe(handler); const std::string TMP = "/tmp/ut-zones"; const std::string NO_PATH = "path_doesnt_matter_here"; @@ -1049,28 +1050,28 @@ BOOST_AUTO_TEST_CASE(MoveFile) const std::string ZONE2PATH = TMP + "/" + ZONE2 + TMP; // sending to a non existing zone - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(BUGGY_ZONE, NO_PATH), + BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(BUGGY_ZONE, NO_PATH), api::zone::FILE_MOVE_DESTINATION_NOT_FOUND); BOOST_CHECK(notificationLatch.empty()); // sending to self - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE1, NO_PATH), + BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE1, NO_PATH), api::zone::FILE_MOVE_WRONG_DESTINATION); BOOST_CHECK(notificationLatch.empty()); // no permission to send - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, "/etc/secret1"), + BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, "/etc/secret1"), api::zone::FILE_MOVE_NO_PERMISSIONS_SEND); BOOST_CHECK(notificationLatch.empty()); // no permission to receive // TODO uncomment this after adding an api to change 'permittedTo*' config - //BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, "/etc/secret2"), + //BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, "/etc/secret2"), // api::zone::FILE_MOVE_NO_PERMISSIONS_RECEIVE); //BOOST_CHECK(notificationLatch.empty()); // non existing file - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, BUGGY_PATH), + BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, BUGGY_PATH), api::zone::FILE_MOVE_FAILED); BOOST_CHECK(notificationLatch.empty()); @@ -1083,7 +1084,7 @@ BOOST_AUTO_TEST_CASE(MoveFile) BOOST_REQUIRE(fs::create_directories(ZONE2PATH, ec)); BOOST_REQUIRE(utils::saveFileContent(ZONE1PATH + "/file", FILE_CONTENT)); - BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(ZONE2, TMP + "/file"), + BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, TMP + "/file"), api::zone::FILE_MOVE_SUCCEEDED); BOOST_REQUIRE(notificationLatch.wait(EVENT_TIMEOUT)); BOOST_REQUIRE(notificationLatch.empty()); @@ -1100,9 +1101,9 @@ BOOST_AUTO_TEST_CASE(MoveFile) BOOST_AUTO_TEST_CASE(AllowSwitchToDefault) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); std::vector> clients; @@ -1150,18 +1151,18 @@ BOOST_AUTO_TEST_CASE(AllowSwitchToDefault) BOOST_AUTO_TEST_CASE(ProxyCall) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); - std::map> dbuses; - dbuses[0] = std::unique_ptr(new HostAccessory()); + std::map> connections; + connections[0] = std::unique_ptr(new HostAccessory()); for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - dbuses[i] = std::unique_ptr(new ZoneAccessory(i)); + connections[i] = std::unique_ptr(new ZoneAccessory(i)); } - for (auto& dbus : dbuses) { + for (auto& dbus : connections) { dbus.second->setName(testapi::BUS_NAME); const int id = dbus.first; @@ -1178,58 +1179,58 @@ BOOST_AUTO_TEST_CASE(ProxyCall) // host -> zone2 BOOST_CHECK_EQUAL("reply from 2: param1", - dbuses.at(0)->testApiProxyCall("zone2", + connections.at(0)->testApiProxyCall("zone2", "param1")); // host -> host BOOST_CHECK_EQUAL("reply from 0: param2", - dbuses.at(0)->testApiProxyCall("host", + connections.at(0)->testApiProxyCall("host", "param2")); // zone1 -> host BOOST_CHECK_EQUAL("reply from 0: param3", - dbuses.at(1)->testApiProxyCall("host", + connections.at(1)->testApiProxyCall("host", "param3")); // zone1 -> zone2 BOOST_CHECK_EQUAL("reply from 2: param4", - dbuses.at(1)->testApiProxyCall("zone2", + connections.at(1)->testApiProxyCall("zone2", "param4")); // zone2 -> zone2 BOOST_CHECK_EQUAL("reply from 2: param5", - dbuses.at(2)->testApiProxyCall("zone2", + connections.at(2)->testApiProxyCall("zone2", "param5")); // host -> unknown - BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("unknown", "param"), + BOOST_CHECK_EXCEPTION(connections.at(0)->testApiProxyCall("unknown", "param"), DbusCustomException, WhatEquals("Unknown proxy call target")); // forwarding error - BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("host", ""), + BOOST_CHECK_EXCEPTION(connections.at(0)->testApiProxyCall("host", ""), DbusCustomException, WhatEquals("Test error")); // forbidden call - BOOST_CHECK_EXCEPTION(dbuses.at(0)->proxyCall("host", - "org.fake", - "/a/b", - "c.d", - "foo", - g_variant_new("(s)", "arg")), + BOOST_CHECK_EXCEPTION(connections.at(0)->proxyCall("host", + "org.fake", + "/a/b", + "c.d", + "foo", + g_variant_new("(s)", "arg")), DbusCustomException, WhatEquals("Proxy call forbidden")); } #endif // DBUS_CONNECTION namespace { - const HostAccessory::Dbuses EXPECTED_DBUSES_NONE = { + const HostAccessory::Connections EXPECTED_CONNECTIONS_NONE = { {"zone1", ""}, {"zone2", ""}, {"zone3", ""}}; - const HostAccessory::Dbuses EXPECTED_DBUSES_ALL = { + const HostAccessory::Connections EXPECTED_CONNECTIONS_ALL = { {"zone1", "unix:path=/tmp/ut-run/zone1/dbus/system_bus_socket"}, {"zone2", @@ -1238,22 +1239,22 @@ namespace { "unix:path=/tmp/ut-run/zone3/dbus/system_bus_socket"}}; } // namespace -BOOST_AUTO_TEST_CASE(GetZoneDbuses) +BOOST_AUTO_TEST_CASE(GetZoneConnections) { ZonesManager cm(TEST_CONFIG_PATH); HostAccessory host; - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); - BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_NONE == host.callMethodGetZoneConnections()); cm.restoreAll(); - BOOST_CHECK(EXPECTED_DBUSES_ALL == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_ALL == host.callMethodGetZoneConnections()); cm.shutdownAll(); - BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_NONE == host.callMethodGetZoneConnections()); } -BOOST_AUTO_TEST_CASE(GetZoneDbusesNoDbus) +BOOST_AUTO_TEST_CASE(GetZoneConnectionsNoDbus) { ZonesManager cm(TEST_CONFIG_PATH); HostAccessory host; @@ -1261,43 +1262,43 @@ BOOST_AUTO_TEST_CASE(GetZoneDbusesNoDbus) cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); - BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_NONE == host.callMethodGetZoneConnections()); cm.restoreAll(); - BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_NONE == host.callMethodGetZoneConnections()); cm.shutdownAll(); - BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses()); + BOOST_CHECK(EXPECTED_CONNECTIONS_NONE == host.callMethodGetZoneConnections()); } -BOOST_AUTO_TEST_CASE(ZoneDbusesSignals) +BOOST_AUTO_TEST_CASE(ZoneConnectionsSignals) { Latch signalLatch; - HostAccessory::Dbuses collectedDbuses; - std::mutex collectedDbusesMutex; + HostAccessory::Connections collectedConnections; + std::mutex collectedConnectionsMutex; - auto onSignal = [&] (const std::string& zoneId, const std::string& dbusAddress) { - std::unique_lock lock(collectedDbusesMutex); - collectedDbuses.insert(HostAccessory::Dbuses::value_type(zoneId, dbusAddress)); + auto onSignal = [&] (const std::string& zoneId, const std::string& address) { + std::unique_lock lock(collectedConnectionsMutex); + collectedConnections.insert(HostAccessory::Connections::value_type(zoneId, address)); signalLatch.set(); }; { ZonesManager cm(TEST_CONFIG_PATH); HostAccessory host; - host.subscribeZoneDbusState(onSignal); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + host.subscribeZoneConnectionState(onSignal); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); BOOST_CHECK(signalLatch.empty()); - BOOST_CHECK(collectedDbuses.empty()); + BOOST_CHECK(collectedConnections.empty()); cm.restoreAll(); BOOST_REQUIRE(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT)); BOOST_CHECK(signalLatch.empty()); - std::unique_lock lock(collectedDbusesMutex); - BOOST_CHECK(EXPECTED_DBUSES_ALL == collectedDbuses); - collectedDbuses.clear(); + std::unique_lock lock(collectedConnectionsMutex); + BOOST_CHECK(EXPECTED_CONNECTIONS_ALL == collectedConnections); + collectedConnections.clear(); } } @@ -1544,8 +1545,8 @@ BOOST_AUTO_TEST_CASE(StartShutdownZone) const std::string zone2 = "zone2"; ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone(zone1, DBUS_TEMPLATE); - cm.createZone(zone2, DBUS_TEMPLATE); + cm.createZone(zone1, ZONE_ACCESS_TEMPLATE); + cm.createZone(zone2, ZONE_ACCESS_TEMPLATE); Latch callDone; auto resultCallback = [&]() { @@ -1581,9 +1582,9 @@ BOOST_AUTO_TEST_CASE(StartShutdownZone) BOOST_AUTO_TEST_CASE(LockUnlockZone) { ZonesManager cm(TEST_CONFIG_PATH); - cm.createZone("zone1", DBUS_TEMPLATE); - cm.createZone("zone2", DBUS_TEMPLATE); - cm.createZone("zone3", DBUS_TEMPLATE); + cm.createZone("zone1", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone2", ZONE_ACCESS_TEMPLATE); + cm.createZone("zone3", ZONE_ACCESS_TEMPLATE); cm.restoreAll(); HostAccessory host; -- 2.7.4