From 69ab55f9b7796150256cc8365684ac0f1630019b Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Thu, 18 Jun 2015 09:43:58 +0200 Subject: [PATCH 01/16] Don't print LOGS messages when log level is greater than TRACE [Bug] LOGS messages was always printed [Cause] N/A [Solution] N/A [Verification] Build, run `vasum-server -r` and `vasum-server -r -l TRACE` Change-Id: Iec4fdd5d40a3920a51afae0a687387cb71b85ea2 --- libs/logger/logger-scope.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/logger/logger-scope.cpp b/libs/logger/logger-scope.cpp index e790bab..a977adc 100644 --- a/libs/logger/logger-scope.cpp +++ b/libs/logger/logger-scope.cpp @@ -43,14 +43,18 @@ LoggerScope::LoggerScope(const std::string& file, mMessage(message), mRootDir(rootDir) { - logger::Logger::logMessage(logger::LogLevel::TRACE, "Entering: " + mMessage, mFile, - mLine, mFunc, mRootDir); + if (logger::Logger::getLogLevel() <= logger::LogLevel::TRACE) { + 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); + if (logger::Logger::getLogLevel() <= logger::LogLevel::TRACE) { + logger::Logger::logMessage(logger::LogLevel::TRACE, "Leaving: " + mMessage, + mFile, mLine, mFunc, mRootDir); + } } } // namespace logger -- 2.7.4 From 35bf91022261d3e35a649f97ba47b26fc742ac6a Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 16 Jun 2015 14:39:42 +0200 Subject: [PATCH 02/16] Add wrapper for lxc-fedora template [Feature] Add wrapper for lxc-fedora template [Cause] N/A [Solution] N/A [Verification] Build, create/start/shutdown/destroy zone. Change-Id: Iaa071f19dedfb7406d576858d8c7be2600b1e077 --- packaging/vasum.spec | 1 + server/configs/templates/fedora.sh | 84 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100755 server/configs/templates/fedora.sh diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 38c7cf6..83c5f0f 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -28,6 +28,7 @@ Requires: lxc Requires: iproute2 Requires(post): libcap-tools %else +Requires: lxc-templates Requires: iproute Requires(post): libcap %endif diff --git a/server/configs/templates/fedora.sh b/server/configs/templates/fedora.sh new file mode 100755 index 0000000..dc4db3b --- /dev/null +++ b/server/configs/templates/fedora.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# template script for creating Fedora LXC container +# This script is a wrapper for the lxc-fedora template +# +# Copyright (c) 2015 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. + +usage() +{ + cat < + [-p|--path=] [--rootfs=] [--vt=] + [--ipv4=] [--ipv4-gateway=] [-h|--help] +Mandatory args: + -n,--name zone name + -p,--path path to zone config files + --rootfs path to zone rootfs +Optional args: + --vt zone virtual terminal + --ipv4 zone IP address + --ipv4-gateway zone gateway + -h,--help print help +EOF + return 0 +} + +options=$(getopt -o hp:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + --rootfs) rootfs=$2; shift 2;; + -p|--path) path=$2; shift 2;; + --vt) vt=$2; shift 2;; + -n|--name) name=$2; shift 2;; + --ipv4) ipv4=$2; shift 2;; + --ipv4-gateway) ipv4_gateway=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z $name ]; then + echo "Zone name must be given" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +if [ -z "$rootfs" ]; then + echo "'rootfs' parameter is required" + exit 1 +fi + +/usr/share/lxc/templates/lxc-fedora --name="$name" --path="$path" --rootfs="$rootfs" -- 2.7.4 From c1df0b7f41eb8a392b6c85f1f1b34b66d84ae967 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 16 Jun 2015 12:56:18 +0200 Subject: [PATCH 03/16] Finish CreateFile API [Feature] N/A [Cause] Missing API [Solution] Add missing functions in ZonesManager and in Communication [Verification] Build, install, run tests Change-Id: I417e1deeca2effcdb772189045263d0c9dd22de7 --- common/api/messages.hpp | 2 + common/lxc/zone.cpp | 8 ++- common/lxc/zone.hpp | 15 +++-- libs/config/from-gvariant-visitor.hpp | 7 +++ libs/config/to-gvariant-visitor.hpp | 2 + server/common-definitions.hpp | 13 +++-- server/host-dbus-connection.cpp | 9 +++ server/host-dbus-definitions.hpp | 1 + server/host-ipc-connection.cpp | 12 ++++ server/host-ipc-connection.hpp | 1 + server/zone.cpp | 9 +++ server/zone.hpp | 11 ++++ server/zones-manager.cpp | 30 ++++++++++ server/zones-manager.hpp | 2 + tests/unit_tests/lxc/ut-zone.cpp | 7 ++- tests/unit_tests/server/ut-zones-manager.cpp | 83 ++++++++++++++++++++++++++++ 16 files changed, 197 insertions(+), 15 deletions(-) diff --git a/common/api/messages.hpp b/common/api/messages.hpp index a00a2dd..7299898 100644 --- a/common/api/messages.hpp +++ b/common/api/messages.hpp @@ -227,11 +227,13 @@ struct GrantDeviceIn { struct CreateFileIn { std::string id; std::string path; + int32_t flags; int32_t mode; CONFIG_REGISTER ( id, path, + flags, mode ) }; diff --git a/common/lxc/zone.cpp b/common/lxc/zone.cpp index 5fd1762..845d959 100644 --- a/common/lxc/zone.cpp +++ b/common/lxc/zone.cpp @@ -376,7 +376,10 @@ bool LxcZone::runInZone(Call& call) return status == 0; } -int LxcZone::createFile(const std::string& path, const std::int32_t mode, int *fdPtr) +bool LxcZone::createFile(const std::string& path, + const std::int32_t flags, + const std::int32_t mode, + int *fdPtr) { *fdPtr = -1; @@ -389,12 +392,13 @@ int LxcZone::createFile(const std::string& path, const std::int32_t mode, int *f lxc::LxcZone::Call call = [&]()->int{ utils::close(sockets[1]); - int fd = ::open(path.c_str(), O_CREAT | O_EXCL, mode); + int fd = ::open(path.c_str(), O_CREAT | O_EXCL | flags, mode); if (fd < 0) { LOGE("Error during file creation: " << utils::getSystemErrorMessage()); utils::close(sockets[0]); return -1; } + LOGT("Created file in zone with fd " << fd); utils::fdSend(sockets[0], fd); utils::close(fd); return 0; diff --git a/common/lxc/zone.hpp b/common/lxc/zone.hpp index 0d34e6f..ff5bb85 100644 --- a/common/lxc/zone.hpp +++ b/common/lxc/zone.hpp @@ -158,12 +158,19 @@ public: /** * Create a file inside the zone and return it's file descriptor * - * @param path path in the container - * @param mode mode + * @param[in] path Path in container where file shall be created + * @param[in] flags Flags used when creating file. Note that the method already provides + * O_CREAT and O_EXCL flags. User must provide the function with + * O_RDWR/O_RDONLY/O_WRONLY flag explicitly. + * @param[in] mode Permissions with which file is created + * @param[out] fdPtr Pointer to opened file descriptor. * - * @return file descriptor of the file, opened in mode + * @return True on success, false on failure. */ - int createFile(const std::string& path, const std::int32_t mode, int *fdPtr); + bool createFile(const std::string& path, + const std::int32_t flags, + const std::int32_t mode, + int *fdPtr); private: lxc_container* mLxcContainer; diff --git a/libs/config/from-gvariant-visitor.hpp b/libs/config/from-gvariant-visitor.hpp index 040dcae..e648625 100644 --- a/libs/config/from-gvariant-visitor.hpp +++ b/libs/config/from-gvariant-visitor.hpp @@ -28,6 +28,7 @@ #include "config/is-visitable.hpp" #include "config/exception.hpp" #include "config/is-union.hpp" +#include "config/types.hpp" #include #include @@ -126,6 +127,12 @@ private: value = g_variant_get_string(object, NULL); } + static void fromGVariant(GVariant* object, config::FileDescriptor& value) + { + checkType(object, G_VARIANT_TYPE_INT32); + value.value = g_variant_get_int32(object); + } + template static void fromGVariant(GVariant* object, std::vector& value) { diff --git a/libs/config/to-gvariant-visitor.hpp b/libs/config/to-gvariant-visitor.hpp index bb94e49..047aa17 100644 --- a/libs/config/to-gvariant-visitor.hpp +++ b/libs/config/to-gvariant-visitor.hpp @@ -27,6 +27,7 @@ #include "config/is-visitable.hpp" #include "config/is-union.hpp" +#include "config/types.hpp" #include #include @@ -82,6 +83,7 @@ private: 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()); }; + void writeInternal(const config::FileDescriptor& value) { add("h", value.value); }; template void writeInternal(const std::vector& value) diff --git a/server/common-definitions.hpp b/server/common-definitions.hpp index 5e85f92..cf8bfe4 100644 --- a/server/common-definitions.hpp +++ b/server/common-definitions.hpp @@ -36,12 +36,13 @@ namespace api { */ //TODO: Errors should use exception handling mechanism ///@{ -const std::string ERROR_FORBIDDEN = "org.tizen.vasum.Error.Forbidden"; -const std::string ERROR_FORWARDED = "org.tizen.vasum.Error.Forwarded"; -const std::string ERROR_INVALID_ID = "org.tizen.vasum.Error.InvalidId"; -const std::string ERROR_INVALID_STATE = "org.tizen.vasum.Error.InvalidState"; -const std::string ERROR_INTERNAL = "org.tizen.vasum.Error.Internal"; -const std::string ERROR_ZONE_NOT_RUNNING = "org.tizen.vasum.Error.ZonesNotRunning"; +const std::string ERROR_FORBIDDEN = "org.tizen.vasum.Error.Forbidden"; +const std::string ERROR_FORWARDED = "org.tizen.vasum.Error.Forwarded"; +const std::string ERROR_INVALID_ID = "org.tizen.vasum.Error.InvalidId"; +const std::string ERROR_INVALID_STATE = "org.tizen.vasum.Error.InvalidState"; +const std::string ERROR_INTERNAL = "org.tizen.vasum.Error.Internal"; +const std::string ERROR_ZONE_NOT_RUNNING = "org.tizen.vasum.Error.ZonesNotRunning"; +const std::string ERROR_CREATE_FILE_FAILED = "org.tizen.vasum.Error.CreateFileFailed"; ///@} } // namespace api diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index 7714b65..ba4e9ee 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -394,6 +394,15 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, mZonesManagerPtr->handleFileMoveCall(EMPTY_CALLER, data, rb); return; } + + if (methodName == api::dbus::METHOD_CREATE_FILE) { + api::CreateFileIn data; + config::loadFromGVariant(parameters, data); + + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCreateFileCall(data, rb); + return; + } } void HostDbusConnection::onSignalCall(const std::string& /* senderBusName */, diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 142a6d2..9b74ab2 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -181,6 +181,7 @@ const std::string DEFINITION = " " " " " " + " " " " " " " " diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index e87adca..c389919 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -125,6 +125,9 @@ HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) setFileMoveCallback(std::bind(&ZonesManager::handleFileMoveCall, mZonesManagerPtr, "", _1, _2)); + + setCreateFileCallback(std::bind(&ZonesManager::handleCreateFileCall, + mZonesManagerPtr, _1, _2)); } HostIPCConnection::~HostIPCConnection() @@ -366,6 +369,15 @@ void HostIPCConnection::setFileMoveCallback(const Method::type& callback) +{ + typedef IPCMethodWrapper Method; + mService->setMethodHandler( + api::ipc::METHOD_CREATE_FILE, + Method::getWrapper(callback)); +} + void HostIPCConnection::sendNotification(const api::Notification& notification) { mService->signal(api::ipc::SIGNAL_NOTIFICATION, diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index 8107612..44fe356 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -86,6 +86,7 @@ private: void setSwitchToDefaultCallback(const Signal::type& callback); void setFileMoveCallback(const Method::type& callback); + void setCreateFileCallback(const Method::type& callback); ipc::epoll::ThreadDispatcher mDispatcher; std::unique_ptr mService; diff --git a/server/zone.cpp b/server/zone.cpp index 94f6873..590badd 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -394,6 +394,15 @@ bool Zone::isSwitchToDefaultAfterTimeoutAllowed() const return mConfig.switchToDefaultAfterTimeout; } +int Zone::createFile(const std::string& path, const std::int32_t flags, const std::int32_t mode) +{ + int fd = 0; + if (!mZone.createFile(path, flags, mode, &fd)) { + throw ZoneOperationException("Failed to create file."); + } + return fd; +} + std::string Zone::declareFile(const int32_t& type, const std::string& path, const int32_t& flags, diff --git a/server/zone.hpp b/server/zone.hpp index 0829c35..dbc384d 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -183,6 +183,17 @@ public: int getVT() const; /** + * Create file inside zone, return its fd + * + * @param path Path where the file should be created + * @param flags Flags used when opening the file. See common/lxc/zone.hpp for more info. + * @param mode Permissions with which file is created + * + * @return Created files fd + */ + int createFile(const std::string& path, const std::int32_t flags, const std::int32_t mode); + + /** * Declare file, directory or pipe that will be created while zone startup */ std::string declareFile(const int32_t& type, diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index d213669..d28c9b4 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -625,6 +625,36 @@ void ZonesManager::handleFileMoveCall(const std::string& /*srcZoneId*/, #endif /* ZONE_CONNECTION */ +void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request, + api::MethodResultBuilder::Pointer result) +{ + auto handler = [&, this] { + LOGI("CreateFile call"); + + Lock lock(mMutex); + + auto srcIter = findZone(request.id); + if (srcIter == mZones.end()) { + LOGE("Zone '" << request.id << "' not found"); + result->setError(api::ERROR_INVALID_ID, "Requested Zone was not found."); + return; + } + Zone& srcZone = get(srcIter); + + auto retValue = std::make_shared(); + try { + retValue->fd = srcZone.createFile(request.path, request.flags, request.mode); + } catch(ZoneOperationException& e) { + result->setError(api::ERROR_CREATE_FILE_FAILED, "Unable to create file"); + return; + } + + result->set(retValue); + }; + + mWorker->addTaskAndWait(handler); +} + #ifdef DBUS_CONNECTION void ZonesManager::handleProxyCall(const std::string& caller, const std::string& target, diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index c74f5ec..55e7023 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -164,6 +164,8 @@ public: api::MethodResultBuilder::Pointer result); void handleRevokeDeviceCall(const api::RevokeDeviceIn& data, api::MethodResultBuilder::Pointer result); + void handleCreateFileCall(const api::CreateFileIn& request, + api::MethodResultBuilder::Pointer result); // Zone's handlers--------------------------------------------------------- void handleNotifyActiveZoneCall(const std::string& caller, diff --git a/tests/unit_tests/lxc/ut-zone.cpp b/tests/unit_tests/lxc/ut-zone.cpp index f87427e..ba839c9 100644 --- a/tests/unit_tests/lxc/ut-zone.cpp +++ b/tests/unit_tests/lxc/ut-zone.cpp @@ -44,6 +44,7 @@ const std::string ZONE_PATH = "/tmp/ut-zone/"; const std::string ZONE_NAME = "ut-zone"; const std::string ZONE_TEMPLATE = VSM_TEST_TEMPLATES_INSTALL_DIR "/minimal.sh"; const char* TEMPLATE_ARGS[] = {NULL}; +const std::int32_t DEFAULT_FILE_MODE = 0666; struct Fixture { utils::ScopedDir mLxcDirGuard; @@ -267,15 +268,15 @@ BOOST_AUTO_TEST_CASE(CreateFile) // The test int fd; - BOOST_REQUIRE(lxc.createFile("./112.txt", O_RDWR, &fd)); + BOOST_REQUIRE(lxc.createFile("./112.txt", O_RDWR, DEFAULT_FILE_MODE, &fd)); BOOST_REQUIRE(::fcntl(fd, F_GETFD) != -1); BOOST_REQUIRE(::close(fd) != -1); - BOOST_REQUIRE(lxc.createFile("/2.txt", O_RDONLY, &fd)); + BOOST_REQUIRE(lxc.createFile("/2.txt", O_RDONLY, DEFAULT_FILE_MODE, &fd)); BOOST_REQUIRE(::fcntl(fd, F_GETFD) != -1); BOOST_REQUIRE(::close(fd) != -1); - BOOST_REQUIRE(lxc.createFile("/3.txt", O_WRONLY, &fd)); + BOOST_REQUIRE(lxc.createFile("/3.txt", O_WRONLY, DEFAULT_FILE_MODE, &fd)); BOOST_REQUIRE(::fcntl(fd, F_GETFD) != -1); BOOST_REQUIRE(::close(fd) != -1); diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 0283fd9..375f212 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -58,6 +58,8 @@ #include #include #include +#include +#include using namespace vasum; using namespace config; @@ -74,6 +76,7 @@ const std::string TEST_CONFIG_PATH = CONFIG_DIR + "/test-daemon.conf"; const std::string MISSING_CONFIG_PATH = CONFIG_DIR + "/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; const int SIGNAL_PROPAGATE_TIME = 500; // ms +const std::int32_t DEFAULT_FILE_MODE = 0666; //const int UNEXPECTED_EVENT_TIMEOUT = EVENT_TIMEOUT / 5; const std::string TEST_APP_NAME = "testapp"; const std::string TEST_MESSAGE = "testmessage"; @@ -445,6 +448,24 @@ public: "()"); } + int callMethodCreateFile(const std::string& id, + const std::string& path, + const std::int32_t& flags, + const std::int32_t& mode) + { + assert(isHost()); + GVariant* parameters = g_variant_new("(ssii)", id.c_str(), path.c_str(), flags, mode); + GVariantPtr result = mClient->callMethod(api::dbus::BUS_NAME, + api::dbus::OBJECT_PATH, + api::dbus::INTERFACE, + api::dbus::METHOD_CREATE_FILE, + parameters, + "(h)"); + int fileFd = 0; + g_variant_get(result.get(), "(h)", &fileFd); + return fileFd; + } + private: const int mId; DbusConnection::Pointer mClient; @@ -599,6 +620,18 @@ public: return result->value; } + int callMethodCreateFile(const std::string& id, + const std::string& path, + const std::int32_t& flags, + const std::int32_t& mode) + { + auto result = mClient.callSync( + api::ipc::METHOD_CREATE_FILE, + std::make_shared(api::CreateFileIn{id, path, flags, mode}), + EVENT_TIMEOUT*10); + return result->fd.value; + } + private: ipc::epoll::ThreadDispatcher mDispatcher; ipc::Client mClient; @@ -1294,4 +1327,54 @@ MULTI_FIXTURE_TEST_CASE(LockUnlockZone, F, ACCESSORS) WhatEquals("Zone is not paused")); } +MULTI_FIXTURE_TEST_CASE(CreateFile, F, ACCESSORS) +{ + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.restoreAll(); + + typename F::HostAccessory host; + int returnedFd = host.callMethodCreateFile("zone1", "/123.txt", O_RDWR, DEFAULT_FILE_MODE); + BOOST_REQUIRE(::fcntl(returnedFd, F_GETFD) != -1); + BOOST_REQUIRE(::close(returnedFd) != -1); + + returnedFd = host.callMethodCreateFile("zone1", "/56.txt", O_RDONLY, DEFAULT_FILE_MODE); + BOOST_REQUIRE(::fcntl(returnedFd, F_GETFD) != -1); + BOOST_REQUIRE(::close(returnedFd) != -1); + + returnedFd = host.callMethodCreateFile("zone1", "/89.txt", O_WRONLY, DEFAULT_FILE_MODE); + BOOST_REQUIRE(::fcntl(returnedFd, F_GETFD) != -1); + BOOST_REQUIRE(::close(returnedFd) != -1); +} + +MULTI_FIXTURE_TEST_CASE(CreateWriteReadFile, F, ACCESSORS) +{ + ZonesManager cm(TEST_CONFIG_PATH); + cm.createZone("zone1", SIMPLE_TEMPLATE); + cm.restoreAll(); + + typename F::HostAccessory host; + + // create file, make sure returned fd is correct + int returnedFd = host.callMethodCreateFile("zone1", "/test123.txt", O_RDWR, DEFAULT_FILE_MODE); + BOOST_REQUIRE(::fcntl(returnedFd, F_GETFD) != -1); + + // write sth + BOOST_REQUIRE_MESSAGE(::write(returnedFd, FILE_CONTENT.c_str(), FILE_CONTENT.size()) > 0, + "Failed to write to fd " << returnedFd << ": " << ::strerror(errno)); + + // go back to the beginning + BOOST_REQUIRE(::lseek(returnedFd, 0, SEEK_SET) != -1); + + // read it back, zero-terminate it and verify + std::unique_ptr retStr(new char[FILE_CONTENT.size()+1]); + BOOST_REQUIRE_MESSAGE(::read(returnedFd, retStr.get(), FILE_CONTENT.size()) > 0, + "Failed to read from file: " << ::strerror(errno)); + retStr[FILE_CONTENT.size()] = 0; + BOOST_REQUIRE(FILE_CONTENT.compare(retStr.get()) == 0); + + // close + BOOST_REQUIRE(::close(returnedFd) != -1); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 5aba67f60ffd9676018e5dd41a016fb682064077 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Fri, 19 Jun 2015 14:49:30 +0200 Subject: [PATCH 04/16] Check vasum runtime - rename vasum-check-env to vasum-check-config [Bug/Feature] naming convention [Cause] N/A [Solution] rename [Verification] N/A Change-Id: I6fb89a9378da7d4c04c0cae74935fdf67df5d3d6 --- packaging/vasum.spec | 2 +- server/CMakeLists.txt | 2 +- server/scripts/{vasum-check-env.sh => vasum-check-config.sh} | 0 server/server.cpp | 8 ++++---- 4 files changed, 6 insertions(+), 6 deletions(-) rename server/scripts/{vasum-check-env.sh => vasum-check-config.sh} (100%) diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 83c5f0f..24c9842 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -45,7 +45,7 @@ between them. A process from inside a zone can request a switch of context %endif %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/vasum-server -%attr(755,root,root) %{_sbindir}/vasum-check-env +%attr(755,root,root) %{_sbindir}/vasum-check-config %dir /etc/vasum %dir /etc/vasum/templates %config /etc/vasum/daemon.conf diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index d5104db..b301d00 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -56,4 +56,4 @@ INSTALL(TARGETS ${SERVER_CODENAME} DESTINATION bin) ## Set capabilities on server executable ####################################### INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE,CAP_SYS_TTY_CONFIG+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})") -INSTALL(PROGRAMS "scripts/vasum-check-env.sh" DESTINATION sbin RENAME vasum-check-env) +INSTALL(PROGRAMS "scripts/vasum-check-config.sh" DESTINATION sbin RENAME vasum-check-config) diff --git a/server/scripts/vasum-check-env.sh b/server/scripts/vasum-check-config.sh similarity index 100% rename from server/scripts/vasum-check-env.sh rename to server/scripts/vasum-check-config.sh diff --git a/server/server.cpp b/server/server.cpp index befb8da..1f749cc 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -163,7 +163,7 @@ bool Server::checkEnvironment() // control-group functionality was merged into kernel version 2.6.24 in 2007 (wikipedia) // namespace support begins from kernels 2.4.19(mnt), 2.6.19(ns,uts,ipc), 2.6.24(pid), 2.6.29(net) // namespace for usr from kernel 3.8(usr) - not used by vasum - std::cout << "kernel is old ver=" << u.release << ", run vasum-check-env" << std::endl; + std::cout << "kernel is old ver=" << u.release << ", run vasum-check-config" << std::endl; return false; } else @@ -184,7 +184,7 @@ bool Server::checkEnvironment() std::string cgroupCheck = "/sys/fs/cgroup"; int fd = ::open(cgroupCheck.c_str(), O_RDONLY); if (fd == -1) { - std::cout << "no cgroups support (can't access " << cgroupCheck << "), run vasum-check-env" << std::endl; + std::cout << "no cgroups support (can't access " << cgroupCheck << "), run vasum-check-config" << std::endl; return false; } @@ -198,7 +198,7 @@ bool Server::checkEnvironment() } ::close(fd); if (err) { - std::cout << "cgroups problem, run vasum-check-env" << std::endl; + std::cout << "cgroups problem, run vasum-check-config" << std::endl; return false; } else @@ -207,7 +207,7 @@ bool Server::checkEnvironment() // check namespaces std::string nsCheck = "/proc/self/ns"; if (::access(nsCheck.c_str(), R_OK|X_OK) == -1) { - std::cout << "no namespace support (can't access " << nsCheck << "), run vasum-check-env" << std::endl; + std::cout << "no namespace support (can't access " << nsCheck << "), run vasum-check-config" << std::endl; return false; } else -- 2.7.4 From bd11817708a85472c67f727081bc4b3f61f24107 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 23 Jun 2015 11:28:51 +0200 Subject: [PATCH 05/16] Fix Klocwork issues [Bug] Issues reported by Klocwork [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I745cccedceff96fc3b1f475da4308f17775a6d24 --- libs/config/from-kvjson-visitor.hpp | 4 ++-- libs/ipc/internals/processor.cpp | 4 ++-- libs/ipc/internals/processor.hpp | 2 +- tests/unit_tests/config/ut-dynvisit.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/config/from-kvjson-visitor.hpp b/libs/config/from-kvjson-visitor.hpp index f9c11ef..943dbb8 100644 --- a/libs/config/from-kvjson-visitor.hpp +++ b/libs/config/from-kvjson-visitor.hpp @@ -212,8 +212,8 @@ private: json_object_put(visitor.mObject); visitor.mObject = nullptr; } - for (int i = 0; i < length; ++i) { - visitor.getValue(i, value[i]); + for (int idx = 0; idx < length; ++idx) { + visitor.getValue(idx, value[idx]); } } diff --git a/libs/ipc/internals/processor.cpp b/libs/ipc/internals/processor.cpp index 9cb86c0..2e7a575 100644 --- a/libs/ipc/internals/processor.cpp +++ b/libs/ipc/internals/processor.cpp @@ -647,7 +647,7 @@ bool Processor::onSendResultRequest(SendResultRequest& request) return false; } -bool Processor::onFinishRequest(FinishRequest& request) +bool Processor::onFinishRequest(FinishRequest& requestFinisher) { LOGS(mLogPrefix + "Processor onFinishRequest"); @@ -686,7 +686,7 @@ bool Processor::onFinishRequest(FinishRequest& request) mIsRunning = false; - request.conditionPtr->notify_all(); + requestFinisher.conditionPtr->notify_all(); return true; } diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index 121978c..a0e39bf 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -466,7 +466,7 @@ private: bool onAddPeerRequest(AddPeerRequest& request); bool onRemovePeerRequest(RemovePeerRequest& request); bool onSendResultRequest(SendResultRequest& request); - bool onFinishRequest(FinishRequest& request); + bool onFinishRequest(FinishRequest& requestFinisher); bool onReturnValue(Peers::iterator& peerIt, const MessageID messageID); diff --git a/tests/unit_tests/config/ut-dynvisit.cpp b/tests/unit_tests/config/ut-dynvisit.cpp index bbe45e0..b2a0372 100644 --- a/tests/unit_tests/config/ut-dynvisit.cpp +++ b/tests/unit_tests/config/ut-dynvisit.cpp @@ -60,7 +60,7 @@ void checkJsonConfig(const TestConfig& cfg, const std::string& json) TestConfig cfg2; loadFromJsonString(json, cfg2); BOOST_CHECK_EQUAL(cfg2.intVal, cfg.intVal); - BOOST_CHECK_EQUAL(cfg.int64Val, cfg.int64Val); + BOOST_CHECK_EQUAL(cfg2.int64Val, cfg.int64Val); BOOST_CHECK_EQUAL(cfg2.boolVal, cfg.boolVal); BOOST_CHECK_EQUAL(cfg2.stringVal, cfg.stringVal); BOOST_CHECK_EQUAL(cfg2.intVector.size(), cfg.intVector.size()); -- 2.7.4 From 335d65d1e88c9c6af913724b720eea80a526f2c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Thu, 25 Jun 2015 10:52:35 +0200 Subject: [PATCH 06/16] Wrapper: send/recv socket fd - based on public domain code [Bug/Feature] Protex reported copy of code from LXC sources [Cause] Copied from vasum old api [Solution] Follow public domain examples from "Unix Network Programming" [Verification] Next protex report Change-Id: I13163a3e0ef68d816ad194e515cab28629a7291f --- wrapper/wrapper-compatibility.cpp | 50 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/wrapper/wrapper-compatibility.cpp b/wrapper/wrapper-compatibility.cpp index 942c5f6..6c3dfa9 100644 --- a/wrapper/wrapper-compatibility.cpp +++ b/wrapper/wrapper-compatibility.cpp @@ -211,65 +211,67 @@ API int sock_recv_fd(int fd, int *recvfd, void *data, size_t size) { LOGS(""); struct msghdr msg; struct iovec iov; + int ret; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(int))]; - char buf[1]; - int ret, *val; + char dummy=1; memset(&msg, 0, sizeof(msg)); msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - iov.iov_base = data ? data : buf; - iov.iov_len = data ? size : sizeof(buf); + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); + + iov.iov_base = data ? data : &dummy; + iov.iov_len = data ? size : sizeof(dummy); msg.msg_iov = &iov; msg.msg_iovlen = 1; ret = recvmsg(fd, &msg, 0); if (ret <= 0) - goto out; + return ret; cmsg = CMSG_FIRSTHDR(&msg); - - *recvfd = -1; - if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - val = (int *)CMSG_DATA(cmsg); - *recvfd = *val; + *recvfd = *((int *)CMSG_DATA(cmsg)); } - out: - return ret; + else + *recvfd = -1; + return ret; } // sock_send_fd API int sock_send_fd(int fd, int sendfd, void *data, size_t size) { LOGS(""); struct msghdr msg; struct iovec iov; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(int))]; - char buf[1]; - int *val; + char dummy=1; memset(&msg, 0, sizeof(msg)); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - val = (int *)(CMSG_DATA(cmsg)); - *val = sendfd; + *((int *)CMSG_DATA(cmsg)) = sendfd; msg.msg_name = NULL; msg.msg_namelen = 0; - iov.iov_base = data ? data : buf; - iov.iov_len = data ? size : sizeof(buf); + iov.iov_base = data ? data : &dummy; + iov.iov_len = data ? size : sizeof(dummy); msg.msg_iov = &iov; msg.msg_iovlen = 1; -- 2.7.4 From c94cb2f9edd0188c3ef54f62ddeeb74fb7b9f6ea Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 24 Jun 2015 16:38:03 +0200 Subject: [PATCH 07/16] Optimization turned off when compiling with coverage support [Feature] Better coverage report [Cause] Optimization can broke coverage report [Solution] Turn off optimization [Verification] Build with 'CCOV' target, run, generate report Change-Id: I13f04d16f6292e5def30a6af75c5fcbc5038fde1 --- CMakeLists.txt | 4 ++-- packaging/vasum.spec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbcf4b9..76a2344 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,8 +63,8 @@ SET(CMAKE_C_FLAGS_DEBUG "-g -O0 -ggdb") SET(CMAKE_CXX_FLAGS_DEBUG "-g -std=${CXX_11_STD} -O0 -ggdb") SET(CMAKE_C_FLAGS_RELEASE "-g -O2 -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELEASE "-g -std=${CXX_11_STD} -O2 -DNDEBUG") -SET(CMAKE_C_FLAGS_CCOV "-g -O2 --coverage") -SET(CMAKE_CXX_FLAGS_CCOV "-g -std=${CXX_11_STD} -O2 --coverage") +SET(CMAKE_C_FLAGS_CCOV "-g -O0 --coverage") +SET(CMAKE_CXX_FLAGS_CCOV "-g -std=${CXX_11_STD} -O0 --coverage") IF(DEFINED SANITIZE) # Enable sanitize build. diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 24c9842..aa6ee22 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -63,7 +63,7 @@ between them. A process from inside a zone can request a switch of context %build %{!?build_type:%define build_type "RELEASE"} -%if %{build_type} == "DEBUG" || %{build_type} == "PROFILING" +%if %{build_type} == "DEBUG" || %{build_type} == "PROFILING" || %{build_type} == "CCOV" CFLAGS="$CFLAGS -Wp,-U_FORTIFY_SOURCE" CXXFLAGS="$CXXFLAGS -Wp,-U_FORTIFY_SOURCE" %endif -- 2.7.4 From faa1396d2fe42048020678b06287dc3573a2b128 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 18 Jun 2015 15:21:38 +0200 Subject: [PATCH 08/16] Implement a Lock/Unlock Queue API calls. [Feature] Calls that make it possible to lock a queue exclusively to one client (IPC/DBUS) which can then order few calls in a row with a guarantee that no other client will interrupt. [Cause] n/a [Solution] n/a [Verification] Built, installed, run tests. Also see below. Additional features implemented in this commit to support the above: - DBus client disconnected notification. Adds a new callback to registerObject() that's called when a client that previously talked to the server gets disconnected. - ZoneManager level client disconnect notification using the aforementioned DBus and already implemented IPC functionalities. - Changed SwitchToDefault from signal to a method so we can return an error code when the queue is locked. - MethodResultBuilder's getID() call that returns ipc independent identifier that client connections can be identified with (using getPeerID and getPeerName from IPC and DBus specific classes respectively). - mGuard fixed in the DbusConnection class. Now it really does protect mConnection and mNameID as well as newly introduced mWatchedClients. - Various half-related fixes/changes here and there (whitespaces, duplicate definition of PROXY_CALL in the DBus interface, etc). There are no tests in this commit for the DBus features and the Lock/Unlock queue. They will follow in the later commits. To somewhat test the disconnect notifications (both, DBus level and ZoneManager level) one can connect to the server using appropriate APIs and watch the DEBUG/TRACE logs. This can be achieved using the following commands: $ dbus-send --system --dest=org.tizen.vasum.host \ --type=method_call --print-reply \ /org/tizen/vasum/host \ org.tizen.vasum.host.manager.GetZoneIds $ vasum-cli get_zone_ids WARNING: this commit breaks API/ABI of libSimpleDbus Change-Id: Ic0ed2371e563c34340ad41d66dd943a1abc8eb48 --- client/vasum-client-impl.cpp | 18 ++++ client/vasum-client-impl.hpp | 10 ++ client/vasum-client.cpp | 10 ++ client/vasum-client.h | 16 ++++ common/api/dbus-method-result-builder.hpp | 9 ++ common/api/ipc-method-result-builder.cpp | 5 + common/api/ipc-method-result-builder.hpp | 3 + common/api/method-result-builder.hpp | 3 +- libs/dbus/connection.cpp | 76 ++++++++++++--- libs/dbus/connection.hpp | 38 +++++++- libs/ipc/method-result.cpp | 5 + libs/ipc/method-result.hpp | 1 + server/common-definitions.hpp | 1 + server/host-dbus-connection.cpp | 34 +++++-- server/host-dbus-connection.hpp | 1 + server/host-dbus-definitions.hpp | 19 ++-- server/host-ipc-connection.cpp | 45 +++++++-- server/host-ipc-connection.hpp | 4 +- server/host-ipc-definitions.hpp | 4 +- server/zones-manager.cpp | 135 +++++++++++++++++++++------ server/zones-manager.hpp | 15 ++- tests/unit_tests/dbus/test-server.cpp | 3 +- tests/unit_tests/dbus/ut-connection.cpp | 20 ++-- tests/unit_tests/server/ut-zones-manager.cpp | 25 ++--- zone-daemon/daemon-connection.cpp | 3 +- 25 files changed, 409 insertions(+), 94 deletions(-) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index f9a15b8..343fd1b 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -308,6 +308,24 @@ VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* /*keys*/, VsmArrayString* }); } +VsmStatus Client::vsm_lock_queue() noexcept +{ + return coverException([&] { + *mClient->callSync( + vasum::api::ipc::METHOD_LOCK_QUEUE, + std::make_shared()); + }); +} + +VsmStatus Client::vsm_unlock_queue() noexcept +{ + return coverException([&] { + *mClient->callSync( + vasum::api::ipc::METHOD_UNLOCK_QUEUE, + std::make_shared()); + }); +} + VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept { return coverException([&] { diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 854c32c..845cf29 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -123,6 +123,16 @@ public: VsmStatus vsm_get_zone_dbuses(VsmArrayString* keys, VsmArrayString* values) noexcept; /** + * @see ::vsm_lock_queue + */ + VsmStatus vsm_lock_queue() noexcept; + + /** + * @see ::vsm_unlock_queue + */ + VsmStatus vsm_unlock_queue() noexcept; + + /** * @see ::vsm_get_zone_ids */ VsmStatus vsm_get_zone_ids(VsmArrayString* array) noexcept; diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index f36c1ed..4acd82a 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -45,6 +45,16 @@ Client& getClient(VsmClient client) } // namespace +API VsmStatus vsm_lock_queue(VsmClient client) +{ + return getClient(client).vsm_lock_queue(); +} + +API VsmStatus vsm_unlock_queue(VsmClient client) +{ + return getClient(client).vsm_unlock_queue(); +} + API VsmStatus vsm_get_poll_fd(VsmClient client, int* fd) { return getClient(client).vsm_get_poll_fd(fd); diff --git a/client/vasum-client.h b/client/vasum-client.h index 3832d23..9216ce9 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -404,6 +404,22 @@ typedef void (*VsmZoneDbusStateCallback)(const char* zoneId, void* data); /** + * Lock the command queue exclusively. + * + * @param[in] client vasum-server's client + * @return status of this function call + */ +VsmStatus vsm_lock_queue(VsmClient client); + +/** + * Unlock the command queue. + * + * @param[in] client vasum-server's client + * @return status of this function call + */ +VsmStatus vsm_unlock_queue(VsmClient client); + +/** * Get dbus address of each zone. * * @param[in] client vasum-server's client diff --git a/common/api/dbus-method-result-builder.hpp b/common/api/dbus-method-result-builder.hpp index c6422dc..7673b65 100644 --- a/common/api/dbus-method-result-builder.hpp +++ b/common/api/dbus-method-result-builder.hpp @@ -39,6 +39,8 @@ namespace vasum { namespace api { +const std::string DBUS_CONNECTION_PREFIX = "dbus://"; + template class DbusMethodResultBuilder: public MethodResultBuilder { public: @@ -49,6 +51,7 @@ private: void setImpl(const std::shared_ptr& data) override; void setVoid() override; void setError(const std::string& name, const std::string& message) override; + std::string getID() const; ::dbus::MethodResultBuilder::Pointer mMethodResultBuilderPtr; std::function)> mSerialize; @@ -82,6 +85,12 @@ void DbusMethodResultBuilder::setError(const std::string& name, const std: mMethodResultBuilderPtr->setError(name, message); } +template +std::string DbusMethodResultBuilder::getID() const +{ + return DBUS_CONNECTION_PREFIX + mMethodResultBuilderPtr->getPeerName(); +} + } // namespace result } // namespace vasum diff --git a/common/api/ipc-method-result-builder.cpp b/common/api/ipc-method-result-builder.cpp index 4ea2845..d7ac681 100644 --- a/common/api/ipc-method-result-builder.cpp +++ b/common/api/ipc-method-result-builder.cpp @@ -48,6 +48,11 @@ void IPCMethodResultBuilder::setError(const std::string& , const std::string& me mMethodResultPtr->setError(1, message); } +std::string IPCMethodResultBuilder::getID() const +{ + return IPC_CONNECTION_PREFIX + std::to_string(mMethodResultPtr->getPeerID()); +} + } // namespace result } // namespace vasum diff --git a/common/api/ipc-method-result-builder.hpp b/common/api/ipc-method-result-builder.hpp index 7b03ece..0b0ddd3 100644 --- a/common/api/ipc-method-result-builder.hpp +++ b/common/api/ipc-method-result-builder.hpp @@ -36,6 +36,8 @@ namespace vasum { namespace api { +const std::string IPC_CONNECTION_PREFIX = "ipc://"; + class IPCMethodResultBuilder: public MethodResultBuilder { public: IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult); @@ -45,6 +47,7 @@ private: void setImpl(const std::shared_ptr& data) override; void setVoid() override; void setError(const std::string& name, const std::string& message) override; + std::string getID() const; ipc::MethodResult::Pointer mMethodResultPtr; }; diff --git a/common/api/method-result-builder.hpp b/common/api/method-result-builder.hpp index 89aa7a9..ca31feb 100644 --- a/common/api/method-result-builder.hpp +++ b/common/api/method-result-builder.hpp @@ -43,6 +43,7 @@ public: virtual ~MethodResultBuilder() {} virtual void setVoid() = 0; virtual void setError(const std::string& name, const std::string& message) = 0; + virtual std::string getID() const = 0; template void set(const std::shared_ptr& data) @@ -52,7 +53,7 @@ public: } private: - virtual void setImpl(const std::shared_ptr& data) =0; + virtual void setImpl(const std::shared_ptr& data) = 0; }; diff --git a/libs/dbus/connection.cpp b/libs/dbus/connection.cpp index 60b3225..ee4cea9 100644 --- a/libs/dbus/connection.cpp +++ b/libs/dbus/connection.cpp @@ -65,6 +65,10 @@ public: g_dbus_method_invocation_return_dbus_error(mInvocation, name.c_str(), message.c_str()); mResultSet = true; } + std::string getPeerName() + { + return std::string(g_dbus_method_invocation_get_sender(mInvocation)); + } private: GDBusMethodInvocation* mInvocation; bool mResultSet; @@ -146,16 +150,19 @@ DbusConnection::DbusConnection(const std::string& address) DbusConnection::~DbusConnection() { // Close connection in a glib thread (because of a bug in glib) - GDBusConnection* connection = mConnection; - guint nameId = mNameId; + auto closeConnection = [this]() { + for (auto client : mWatchedClients) { + LOGT("Stopped watching the client: " << client.first); + g_bus_unwatch_name(client.second); + } - auto closeConnection = [=]() { - if (nameId) { - g_bus_unown_name(nameId); + if (mNameId) { + g_bus_unown_name(mNameId); } - g_object_unref(connection); + g_object_unref(mConnection); LOGT("Connection deleted"); }; + executeInGlibThread(closeConnection, mGuard); } @@ -268,7 +275,8 @@ std::string DbusConnection::introspect(const std::string& busName, const std::st void DbusConnection::registerObject(const std::string& objectPath, const std::string& objectDefinitionXml, - const MethodCallCallback& callback) + const MethodCallCallback& methodCall, + const ClientVanishedCallback& clientVanished) { ScopedGError error; GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(objectDefinitionXml.c_str(), &error); @@ -297,8 +305,10 @@ void DbusConnection::registerObject(const std::string& objectPath, objectPath.c_str(), interfaceInfo, &vtable, - createCallbackWrapper(callback, mGuard.spawn()), - &deleteCallbackWrapper, + createCallbackWrapper( + MethodCallbacks(methodCall, clientVanished, this), + mGuard.spawn()), + &deleteCallbackWrapper, &error); g_dbus_node_info_unref(nodeInfo); if (error) { @@ -308,7 +318,7 @@ void DbusConnection::registerObject(const std::string& objectPath, } } -void DbusConnection::onMethodCall(GDBusConnection*, +void DbusConnection::onMethodCall(GDBusConnection* connection, const gchar*, const gchar* objectPath, const gchar* interface, @@ -317,14 +327,54 @@ void DbusConnection::onMethodCall(GDBusConnection*, GDBusMethodInvocation* invocation, gpointer userData) { - const MethodCallCallback& callback = getCallbackFromPointer(userData); + const MethodCallbacks& callbacks = getCallbackFromPointer(userData); LOGD("MethodCall: " << objectPath << "; " << interface << "; " << method); + const gchar *sender = g_dbus_method_invocation_get_sender(invocation); + ClientsMap &watchedClients = callbacks.dbusConn->mWatchedClients; + + if (watchedClients.find(sender) == watchedClients.end()) { + LOGT("Watching the client: " << sender); + guint id = g_bus_watch_name_on_connection(connection, + sender, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, + &DbusConnection::onClientVanish, + createCallbackWrapper( + VanishedCallbacks(callbacks.clientVanished, + watchedClients), + callbacks.dbusConn->mGuard.spawn()), + &deleteCallbackWrapper); + + watchedClients[sender] = id; + } + MethodResultBuilder::Pointer resultBuilder(new MethodResultBuilderImpl(invocation)); - if (callback) { - callback(objectPath, interface, method, parameters, resultBuilder); + if (callbacks.methodCall) { + callbacks.methodCall(objectPath, interface, method, parameters, resultBuilder); + } +} + +void DbusConnection::onClientVanish(GDBusConnection*, + const gchar *name, + gpointer userData) +{ + const VanishedCallbacks& callbacks = getCallbackFromPointer(userData); + + LOGI("ClientVanished: " << name); + + guint id = callbacks.watchedClients[name]; + callbacks.watchedClients.erase(name); + + if (callbacks.clientVanished) { + callbacks.clientVanished(name); } + + LOGT("Stopped watching the client: " << name); + + // after this line we cannot use the *name pointer, this call frees it + g_bus_unwatch_name(id); } GVariantPtr DbusConnection::callMethod(const std::string& busName, diff --git a/libs/dbus/connection.hpp b/libs/dbus/connection.hpp index 5248d2e..fc7f1f7 100644 --- a/libs/dbus/connection.hpp +++ b/libs/dbus/connection.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -49,6 +50,7 @@ public: virtual void set(GVariant* parameters) = 0; virtual void setVoid() = 0; virtual void setError(const std::string& name, const std::string& message) = 0; + virtual std::string getPeerName() = 0; }; /** @@ -80,6 +82,9 @@ public: MethodResultBuilder::Pointer result )> MethodCallCallback; + typedef std::function ClientVanishedCallback; + typedef std::function ClientsMap; + + struct MethodCallbacks { + MethodCallCallback methodCall; + ClientVanishedCallback clientVanished; + DbusConnection *dbusConn; + + MethodCallbacks(const MethodCallCallback& method, + const ClientVanishedCallback& vanish, + DbusConnection *dbus) + : methodCall(method), clientVanished(vanish), dbusConn(dbus) {} + }; + + struct VanishedCallbacks { + ClientVanishedCallback clientVanished; + ClientsMap &watchedClients; + + VanishedCallbacks(const ClientVanishedCallback& vanish, ClientsMap& clients) + : clientVanished(vanish), watchedClients(clients) {} + }; + GDBusConnection* mConnection; guint mNameId; + // It's only ever modified in the glib thread + ClientsMap mWatchedClients; + // Guard must be destroyed before objects it protects + // (e.g. all of the above, see the destructor) + utils::CallbackGuard mGuard; DbusConnection(const std::string& address); @@ -207,6 +238,9 @@ private: static void onAsyncReady(GObject* source, GAsyncResult* asyncResult, gpointer userData); + static void onClientVanish(GDBusConnection* connection, + const gchar *name, + gpointer userData); }; diff --git a/libs/ipc/method-result.cpp b/libs/ipc/method-result.cpp index ffb97a8..97eb450 100644 --- a/libs/ipc/method-result.cpp +++ b/libs/ipc/method-result.cpp @@ -54,4 +54,9 @@ void MethodResult::setError(const int code, const std::string& message) mProcessor.sendError(mPeerID, mMessageID, code, message); } +PeerID MethodResult::getPeerID() +{ + return mPeerID; +} + } // namespace ipc diff --git a/libs/ipc/method-result.hpp b/libs/ipc/method-result.hpp index bd9d10f..26369ed 100644 --- a/libs/ipc/method-result.hpp +++ b/libs/ipc/method-result.hpp @@ -51,6 +51,7 @@ public: void setVoid(); void setError(const int code, const std::string& message); + PeerID getPeerID(); private: Processor& mProcessor; diff --git a/server/common-definitions.hpp b/server/common-definitions.hpp index cf8bfe4..b7b22ed 100644 --- a/server/common-definitions.hpp +++ b/server/common-definitions.hpp @@ -43,6 +43,7 @@ const std::string ERROR_INVALID_STATE = "org.tizen.vasum.Error.InvalidState const std::string ERROR_INTERNAL = "org.tizen.vasum.Error.Internal"; const std::string ERROR_ZONE_NOT_RUNNING = "org.tizen.vasum.Error.ZonesNotRunning"; const std::string ERROR_CREATE_FILE_FAILED = "org.tizen.vasum.Error.CreateFileFailed"; +const std::string ERROR_QUEUE = "org.tizen.vasum.Error.Queue"; ///@} } // namespace api diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index ba4e9ee..20cffd9 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -70,7 +70,9 @@ HostDbusConnection::HostDbusConnection(ZonesManager* zonesManagerPtr) mDbusConnection->registerObject(api::dbus::OBJECT_PATH, api::dbus::DEFINITION, std::bind(&HostDbusConnection::onMessageCall, - this, _1, _2, _3, _4, _5)); + this, _1, _2, _3, _4, _5), + std::bind(&HostDbusConnection::onClientVanished, + this, _1)); mSubscriptionId = mDbusConnection->signalSubscribe(std::bind(&HostDbusConnection::onSignalCall, this, _1, _2, _3, _4, _5), @@ -168,6 +170,18 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, return; } + if (methodName == api::dbus::METHOD_LOCK_QUEUE) { + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleLockQueueCall(rb); + return; + } + + if (methodName == api::dbus::METHOD_UNLOCK_QUEUE) { + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleUnlockQueueCall(rb); + return; + } + if (methodName == api::dbus::METHOD_GET_ZONE_ID_LIST) { auto rb = std::make_shared>(result); mZonesManagerPtr->handleGetZoneIdsCall(rb); @@ -403,21 +417,29 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, mZonesManagerPtr->handleCreateFileCall(data, rb); return; } + + if (methodName == api::dbus::METHOD_SWITCH_TO_DEFAULT) { + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER, rb); + return; + } +} + +void HostDbusConnection::onClientVanished(const std::string& name) +{ + const std::string id = api::DBUS_CONNECTION_PREFIX + name; + mZonesManagerPtr->disconnectedCallback(id); } void HostDbusConnection::onSignalCall(const std::string& /* senderBusName */, const std::string& objectPath, const std::string& interface, - const std::string& signalName, + const std::string& /* signalName */, GVariant* /* parameters */) { if (objectPath != api::dbus::OBJECT_PATH || interface != api::dbus::INTERFACE) { return; } - - if (signalName == api::dbus::SIGNAL_SWITCH_TO_DEFAULT) { - mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER); - } } void HostDbusConnection::proxyCallAsync(const std::string& busName, diff --git a/server/host-dbus-connection.hpp b/server/host-dbus-connection.hpp index 23bb9d9..2b4d2a3 100644 --- a/server/host-dbus-connection.hpp +++ b/server/host-dbus-connection.hpp @@ -97,6 +97,7 @@ private: const std::string& methodName, GVariant* parameters, dbus::MethodResultBuilder::Pointer result); + void onClientVanished(const std::string& name); void onSignalCall(const std::string& senderBusName, const std::string& objectPath, const std::string& interface, diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 9b74ab2..caa333b 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -63,11 +63,13 @@ const std::string METHOD_GRANT_DEVICE = "GrantDevice"; const std::string METHOD_REVOKE_DEVICE = "RevokeDevice"; const std::string METHOD_PROXY_CALL = "ProxyCall"; const std::string METHOD_CREATE_FILE = "CreateFile"; +const std::string METHOD_LOCK_QUEUE = "LockQueue"; +const std::string METHOD_UNLOCK_QUEUE = "UnlockQueue"; +const std::string METHOD_SWITCH_TO_DEFAULT = "SwitchToDefault"; const std::string METHOD_NOTIFY_ACTIVE_ZONE = "NotifyActiveZone"; const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest"; const std::string SIGNAL_NOTIFICATION = "Notification"; -const std::string SIGNAL_SWITCH_TO_DEFAULT = "SwitchToDefault"; const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND"; const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION"; @@ -80,14 +82,9 @@ const std::string FILE_MOVE_SUCCEEDED = "FILE_MOVE_SUCCEEDED"; const std::string DEFINITION = "" " " - " " - " " - " " - " " - " " - " " - " " - " " + " " + " " + " " " " " " " " @@ -227,13 +224,13 @@ const std::string DEFINITION = " " " " " " + " " + " " " " " " " " " " " " - " " - " " " " ""; diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index c389919..f110999 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -39,9 +39,22 @@ HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) : mZonesManagerPtr(zonesManagerPtr) { LOGT("Connecting to host IPC socket"); - mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET)); + + ipc::PeerCallback removedCallback = [this](const ipc::PeerID peerID, + const ipc::FileDescriptor) { + std::string id = api::IPC_CONNECTION_PREFIX + std::to_string(peerID); + mZonesManagerPtr->disconnectedCallback(id); + }; + mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET, + nullptr, removedCallback)); using namespace std::placeholders; + setLockQueueCallback(std::bind(&ZonesManager::handleLockQueueCall, + mZonesManagerPtr, _1)); + + setUnlockQueueCallback(std::bind(&ZonesManager::handleUnlockQueueCall, + mZonesManagerPtr, _1)); + setGetZoneIdsCallback(std::bind(&ZonesManager::handleGetZoneIdsCall, mZonesManagerPtr, _1)); @@ -121,7 +134,7 @@ HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) mZonesManagerPtr, "", _1, _2)); setSwitchToDefaultCallback(std::bind(&ZonesManager::handleSwitchToDefaultCall, - mZonesManagerPtr, "")); + mZonesManagerPtr, "", _1)); setFileMoveCallback(std::bind(&ZonesManager::handleFileMoveCall, mZonesManagerPtr, "", _1, _2)); @@ -141,13 +154,28 @@ void HostIPCConnection::start() LOGD("Connected"); } +void HostIPCConnection::setLockQueueCallback(const Method::type& callback) +{ + typedef IPCMethodWrapper Callback; + mService->setMethodHandler( + api::ipc::METHOD_LOCK_QUEUE, + Callback::getWrapper(callback)); +} + +void HostIPCConnection::setUnlockQueueCallback(const Method::type& callback) +{ + typedef IPCMethodWrapper Callback; + mService->setMethodHandler( + api::ipc::METHOD_UNLOCK_QUEUE, + Callback::getWrapper(callback)); +} + void HostIPCConnection::setGetZoneIdsCallback(const Method::type& callback) { typedef IPCMethodWrapper Callback; mService->setMethodHandler( api::ipc::METHOD_GET_ZONE_ID_LIST, Callback::getWrapper(callback)); - } void HostIPCConnection::setGetActiveZoneIdCallback(const Method::type& callback) @@ -156,7 +184,6 @@ void HostIPCConnection::setGetActiveZoneIdCallback(const Method::ty mService->setMethodHandler( api::ipc::METHOD_GET_ACTIVE_ZONE_ID, Callback::getWrapper(callback)); - } void HostIPCConnection::setGetZoneInfoCallback(const Method::type& callback) @@ -352,12 +379,12 @@ void HostIPCConnection::setNotifyActiveZoneCallback( Method::getWrapper(callback)); } -void HostIPCConnection::setSwitchToDefaultCallback(const Signal::type& callback) +void HostIPCConnection::setSwitchToDefaultCallback(const Method::type& callback) { - typedef IPCSignalWrapper Signal; - mService->setSignalHandler( - api::ipc::SIGNAL_SWITCH_TO_DEFAULT, - Signal::getWrapper(callback)); + typedef IPCMethodWrapper Callback; + mService->setMethodHandler( + api::ipc::METHOD_SWITCH_TO_DEFAULT, + Callback::getWrapper(callback)); } void HostIPCConnection::setFileMoveCallback(const Method::type& callback); + void setUnlockQueueCallback(const Method::type& callback); void setGetZoneIdsCallback(const Method::type& callback); void setGetZoneConnectionsCallback(const Method::type& callback); void setGetActiveZoneIdCallback(const Method::type& callback); @@ -83,7 +85,7 @@ private: void setGrantDeviceCallback(const Method::type& callback); void setRevokeDeviceCallback(const Method::type& callback); void setNotifyActiveZoneCallback(const Method::type& callback); - void setSwitchToDefaultCallback(const Signal::type& callback); + void setSwitchToDefaultCallback(const Method::type& callback); void setFileMoveCallback(const Method::type& callback); void setCreateFileCallback(const Method::type& callback); diff --git a/server/host-ipc-definitions.hpp b/server/host-ipc-definitions.hpp index d1251eb..74cf534 100644 --- a/server/host-ipc-definitions.hpp +++ b/server/host-ipc-definitions.hpp @@ -57,11 +57,13 @@ const ::ipc::MethodID METHOD_UNLOCK_ZONE = 24; const ::ipc::MethodID METHOD_GRANT_DEVICE = 25; const ::ipc::MethodID METHOD_REVOKE_DEVICE = 26; const ::ipc::MethodID METHOD_CREATE_FILE = 27; +const ::ipc::MethodID METHOD_LOCK_QUEUE = 28; +const ::ipc::MethodID METHOD_UNLOCK_QUEUE = 29; +const ::ipc::MethodID METHOD_SWITCH_TO_DEFAULT = 30; const ::ipc::MethodID METHOD_NOTIFY_ACTIVE_ZONE = 100; const ::ipc::MethodID METHOD_FILE_MOVE_REQUEST = 101; const ::ipc::MethodID SIGNAL_NOTIFICATION = 102; -const ::ipc::MethodID SIGNAL_SWITCH_TO_DEFAULT = 103; const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND"; const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION"; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index d28c9b4..a0a0205 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -116,6 +116,7 @@ ZonesManager::ZonesManager(const std::string& configPath) : mWorker(utils::Worker::create()) , mHostIPCConnection(this) , mDetachOnExit(false) + , mExclusiveIDLock(INVALID_CONNECTION_ID) #ifdef DBUS_CONNECTION , mHostDbusConnection(this) #endif @@ -251,6 +252,25 @@ void ZonesManager::insertZone(const std::string& zoneId, const std::string& zone } } +void ZonesManager::tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait) +{ + { + Lock lock(mExclusiveIDMutex); + + if (mExclusiveIDLock != INVALID_CONNECTION_ID && + mExclusiveIDLock != result->getID()) { + result->setError(api::ERROR_QUEUE, "Queue is locked by another client"); + return; + } + } + + if (wait) { + mWorker->addTaskAndWait(task); + } else { + mWorker->addTask(task); + } +} + void ZonesManager::destroyZone(const std::string& zoneId) { Lock lock(mMutex); @@ -465,7 +485,21 @@ void ZonesManager::setZonesDetachOnExit() } } -void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/) +void ZonesManager::disconnectedCallback(const std::string& id) +{ + LOGD("Client Disconnected: " << id); + + { + Lock lock(mExclusiveIDMutex); + + if (mExclusiveIDLock == id) { + mExclusiveIDLock = INVALID_CONNECTION_ID; + } + } +} + +void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/, + api::MethodResultBuilder::Pointer result) { auto handler = [&, this] { // get config of currently set zone and switch if switchToDefaultAfterTimeout is true @@ -482,9 +516,10 @@ void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/) LOGI("Switching to default zone " << mDynamicConfig.defaultId); focusInternal(defaultIter); } + result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } #ifdef ZONE_CONNECTION @@ -512,7 +547,7 @@ void ZonesManager::handleNotifyActiveZoneCall(const std::string& caller, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleFileMoveCall(const std::string& srcZoneId, @@ -606,7 +641,7 @@ void ZonesManager::handleFileMoveCall(const std::string& srcZoneId, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } #else void ZonesManager::handleNotifyActiveZoneCall(const std::string& /* caller */, @@ -652,7 +687,7 @@ void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request, result->set(retValue); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } #ifdef DBUS_CONNECTION @@ -703,10 +738,53 @@ void ZonesManager::handleProxyCall(const std::string& caller, asyncResultCallback); }; + // This call cannot be locked by lock/unlock queue mWorker->addTaskAndWait(handler); } #endif //DBUS_CONNECTION +void ZonesManager::handleLockQueueCall(api::MethodResultBuilder::Pointer result) +{ + Lock lock(mExclusiveIDMutex); + std::string id = result->getID(); + + LOGI("Lock Queue: " << id); + + if (mExclusiveIDLock == id) { + result->setError(api::ERROR_QUEUE, "Queue already locked"); + return; + } + + if (mExclusiveIDLock != INVALID_CONNECTION_ID) { + result->setError(api::ERROR_QUEUE, "Queue locked by another connection"); + return; + } + + mExclusiveIDLock = id; + result->setVoid(); +} + +void ZonesManager::handleUnlockQueueCall(api::MethodResultBuilder::Pointer result) +{ + Lock lock(mExclusiveIDMutex); + std::string id = result->getID(); + + LOGI("Unlock Queue: " << id); + + if (mExclusiveIDLock == INVALID_CONNECTION_ID) { + result->setError(api::ERROR_QUEUE, "Queue not locked"); + return; + } + + if (mExclusiveIDLock != id) { + result->setError(api::ERROR_QUEUE, "Queue locked by another connection"); + return; + } + + mExclusiveIDLock = INVALID_CONNECTION_ID; + result->setVoid(); +} + void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result) { auto handler = [&, this] { @@ -722,6 +800,7 @@ void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result result->set(zoneIds); }; + // This call cannot be locked by lock/unlock queue mWorker->addTaskAndWait(handler); } @@ -735,6 +814,7 @@ void ZonesManager::handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer r result->set(zoneId); }; + // This call cannot be locked by lock/unlock queue mWorker->addTaskAndWait(handler); } @@ -774,6 +854,7 @@ void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId, result->set(zoneInfo); }; + // This call cannot be locked by lock/unlock queue mWorker->addTaskAndWait(handler); } @@ -803,7 +884,7 @@ void ZonesManager::handleSetNetdevAttrsCall(const api::SetNetDevAttrsIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data, @@ -830,7 +911,7 @@ void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId, @@ -853,7 +934,7 @@ void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data, @@ -876,7 +957,7 @@ void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& dat } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data, @@ -898,7 +979,7 @@ void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanI } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data, @@ -921,7 +1002,7 @@ void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& dat } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data, @@ -944,7 +1025,7 @@ void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data, @@ -966,7 +1047,7 @@ void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddr } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data, @@ -989,7 +1070,7 @@ void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data, @@ -1012,7 +1093,7 @@ void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data, @@ -1035,7 +1116,7 @@ void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId, @@ -1058,7 +1139,7 @@ void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId, } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data, @@ -1080,7 +1161,7 @@ void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& d } }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId, @@ -1109,7 +1190,7 @@ void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId, result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } @@ -1255,7 +1336,7 @@ void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data, } }; - mWorker->addTaskAndWait(creator); + tryAddTask(creator, result, true); } void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId, @@ -1276,7 +1357,7 @@ void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId, result->setVoid(); }; - mWorker->addTask(destroyer); + tryAddTask(destroyer, result, false); } void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId, @@ -1305,7 +1386,7 @@ void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId, } }; - mWorker->addTask(shutdown); + tryAddTask(shutdown, result, false); } void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId, @@ -1332,7 +1413,7 @@ void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId, result->setError(api::ERROR_INTERNAL, "Failed to start zone"); } }; - mWorker->addTask(startAsync); + tryAddTask(startAsync, result, false); } void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId, @@ -1371,7 +1452,7 @@ void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId, result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId, @@ -1408,7 +1489,7 @@ void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId, result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data, @@ -1451,7 +1532,7 @@ void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data, result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data, @@ -1492,7 +1573,7 @@ void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data, result->setVoid(); }; - mWorker->addTaskAndWait(handler); + tryAddTask(handler, result, true); } } // namespace vasum diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 55e7023..e7b6675 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -45,6 +45,8 @@ namespace vasum { +const std::string INVALID_CONNECTION_ID = "invalid://"; + class ZonesManager final { public: @@ -115,7 +117,14 @@ public: */ void setZonesDetachOnExit(); + /** + * Callback on a client (ipc/dbus) disconnect + */ + void disconnectedCallback(const std::string& id); + // Handlers -------------------------------------------------------- + void handleLockQueueCall(api::MethodResultBuilder::Pointer result); + void handleUnlockQueueCall(api::MethodResultBuilder::Pointer result); void handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result); void handleGetZoneInfoCall(const api::ZoneId& data, @@ -171,7 +180,8 @@ public: void handleNotifyActiveZoneCall(const std::string& caller, const api::NotifActiveZoneIn& notif, api::MethodResultBuilder::Pointer result); - void handleSwitchToDefaultCall(const std::string& caller); + void handleSwitchToDefaultCall(const std::string& caller, + api::MethodResultBuilder::Pointer result); void handleFileMoveCall(const std::string& srcZoneId, const api::FileMoveRequestIn& request, api::MethodResultBuilder::Pointer result); @@ -193,6 +203,8 @@ private: Zones mZones; std::string mActiveZoneId; bool mDetachOnExit; + std::string mExclusiveIDLock; + Mutex mExclusiveIDMutex; // used to protect mExclusiveIDLock Zones::iterator findZone(const std::string& id); Zone& getZone(const std::string& id); @@ -209,6 +221,7 @@ private: std::string getTemplatePathForExistingZone(const std::string& id); int getVTForNewZone(); void insertZone(const std::string& zoneId, const std::string& templatePath); + void tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait); #ifdef DBUS_CONNECTION HostDbusConnection mHostDbusConnection; diff --git a/tests/unit_tests/dbus/test-server.cpp b/tests/unit_tests/dbus/test-server.cpp index a0fee4c..03a4046 100644 --- a/tests/unit_tests/dbus/test-server.cpp +++ b/tests/unit_tests/dbus/test-server.cpp @@ -50,7 +50,8 @@ DbusTestServer::DbusTestServer() using namespace std::placeholders; mConnection->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, - std::bind(&DbusTestServer::onMessageCall, this, _1, _2, _3, _4, _5)); + std::bind(&DbusTestServer::onMessageCall, this, _1, _2, _3, _4, _5), + nullptr); } bool DbusTestServer::waitForName() diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 98154df..6cefb1c 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -265,13 +265,13 @@ BOOST_AUTO_TEST_CASE(RegisterObject) ScopedGlibLoop loop; DbusConnection::Pointer conn = DbusConnection::create(DBUS_ADDRESS); DbusConnection::MethodCallCallback callback; - BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "registerObject(TESTAPI_OBJECT_PATH, "registerObject(TESTAPI_OBJECT_PATH, "", callback), + BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback, nullptr), DbusInvalidArgumentException); - BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback), + BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback, nullptr), DbusInvalidArgumentException); - BOOST_CHECK_NO_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, callback)); + BOOST_CHECK_NO_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, callback, nullptr)); } BOOST_AUTO_TEST_CASE(IntrospectSystem) @@ -298,7 +298,8 @@ BOOST_AUTO_TEST_CASE(Introspect) BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT)); conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, - DbusConnection::MethodCallCallback()); + DbusConnection::MethodCallCallback(), + nullptr); std::string xml = conn2->introspect(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH); std::string iface = getInterfaceFromIntrospectionXML(xml, TESTAPI_INTERFACE); BOOST_REQUIRE(!iface.empty()); @@ -343,7 +344,7 @@ BOOST_AUTO_TEST_CASE(MethodCall) result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg)); } }; - conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); + conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr); GVariantPtr result1 = conn2->callMethod(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, @@ -407,7 +408,7 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCall) result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg)); } }; - conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); + conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr); auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { if (g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)) { @@ -491,7 +492,7 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandler) handlerDone.set(); } }; - conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); + conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr); auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { const gchar* ret = NULL; @@ -528,7 +529,8 @@ BOOST_AUTO_TEST_CASE(MethodCallException) BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT)); conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, - DbusConnection::MethodCallCallback()); + DbusConnection::MethodCallCallback(), + nullptr); BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH, TESTAPI_INTERFACE, diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 375f212..125d857 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -192,13 +192,14 @@ public: mClient->signalSubscribe(handler, api::dbus::BUS_NAME); } - void signalSwitchToDefault() + void callSwitchToDefault() { - // emit signal from dbus connection - mClient->emitSignal(api::dbus::OBJECT_PATH, + mClient->callMethod(api::dbus::BUS_NAME, + api::dbus::OBJECT_PATH, api::dbus::INTERFACE, - api::dbus::SIGNAL_SWITCH_TO_DEFAULT, - nullptr); + api::dbus::METHOD_SWITCH_TO_DEFAULT, + NULL, + "()"); } void callMethodNotify() @@ -244,7 +245,7 @@ public: } } }; - mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler); + mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler, nullptr); } std::string testApiProxyCall(const std::string& target, const std::string& argument) @@ -598,9 +599,11 @@ public: callbackWrapper); } - void signalSwitchToDefault() + void callSwitchToDefault() { - mClient.signal(api::ipc::SIGNAL_SWITCH_TO_DEFAULT, std::make_shared()); + mClient.callSync(api::ipc::METHOD_SWITCH_TO_DEFAULT, + std::make_shared(), + EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone } void callMethodNotify() @@ -912,7 +915,7 @@ MULTI_FIXTURE_TEST_CASE(SwitchToDefault, F, ACCESSORS) cm.focus("zone3"); - host.signalSwitchToDefault(); + host.callSwitchToDefault(); // check if default zone has focus BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused)); @@ -936,7 +939,7 @@ MULTI_FIXTURE_TEST_CASE(AllowSwitchToDefault, F, ACCESSORS) // focus non-default zone with allowed switching cm.focus("zone3"); - host.signalSwitchToDefault(); + host.callSwitchToDefault(); // check if default zone has focus BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused)); @@ -944,7 +947,7 @@ MULTI_FIXTURE_TEST_CASE(AllowSwitchToDefault, F, ACCESSORS) // focus non-default zone with disabled switching cm.focus("zone2"); - host.signalSwitchToDefault(); + host.callSwitchToDefault(); // now default zone should not be focused // TODO uncomment this after adding an api to change 'switchToDefaultAfterTimeout' diff --git a/zone-daemon/daemon-connection.cpp b/zone-daemon/daemon-connection.cpp index 94a84a8..3fb40ac 100644 --- a/zone-daemon/daemon-connection.cpp +++ b/zone-daemon/daemon-connection.cpp @@ -72,7 +72,8 @@ DaemonConnection::DaemonConnection(const NameLostCallback& nameLostCallback, mDbusConnection->registerObject(zone_daemon::api::OBJECT_PATH, zone_daemon::api::DEFINITION, std::bind(&DaemonConnection::onMessageCall, - this, _1, _2, _3, _4, _5)); + this, _1, _2, _3, _4, _5), + nullptr); LOGD("Connected"); } -- 2.7.4 From 68dd3c4d1edb5d38a404c70e1bfa16326d68ed68 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Mon, 22 Jun 2015 10:59:52 +0200 Subject: [PATCH 09/16] Various changes relating to Fedora Linux support. [Bug/Feature] Fix vasum-cli create_zone (add zone template name parameter). Default zone template depends on target platform. Create zones data directory. Add fedora zone template. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run daemon, create/start/shutdown/destroy zone. Change-Id: I63b4b6a60c85b826492e13d016f67e489cefb36c --- cli/command-line-interface.cpp | 2 +- cli/main.cpp | 5 ++-- packaging/vasum.spec | 5 ++++ server/configs/CMakeLists.txt | 2 +- server/configs/templates/fedora.conf | 21 +++++++++++++++ server/configs/templates/template.sh | 6 +++-- server/configs/templates/tizen-common-wayland.sh | 6 +++-- .../configs/templates/{default.conf => tizen.conf} | 0 server/zones-manager.cpp | 30 ++++++++++++---------- 9 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 server/configs/templates/fedora.conf rename server/configs/templates/{default.conf => tizen.conf} (100%) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index 2393ce1..0c28cdd 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -220,7 +220,7 @@ void create_zone(int pos, int argc, const char** argv) throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_create_zone, _1, argv[pos + 1], nullptr)); + one_shot(bind(vsm_create_zone, _1, argv[pos + 1], argv[pos + 2] ? argv[pos + 2] : nullptr)); } void destroy_zone(int pos, int argc, const char** argv) diff --git a/cli/main.cpp b/cli/main.cpp index 6c10945..af36c74 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -47,9 +47,10 @@ std::map commands = { { "create_zone", { create_zone, - "create_zone zone_id", + "create_zone zone_id [zone_tname]", "Create and add zone", - {{"zone_id", "id zone name"}} + {{"zone_id", "id zone name"}, + {"[zone_tname]", "optional zone template name"}} } }, { diff --git a/packaging/vasum.spec b/packaging/vasum.spec index aa6ee22..13112b5 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -86,6 +86,11 @@ make -k %{?jobs:-j%jobs} mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants ln -s ../vasum.service %{buildroot}/%{_unitdir}/multi-user.target.wants/vasum.service mkdir -p %{buildroot}/%{_datadir}/zones +%if %{platform_type} == "TIZEN" +ln -s tizen.conf %{buildroot}/etc/vasum/templates/default.conf +%else +ln -s fedora.conf %{buildroot}/etc/vasum/templates/default.conf +%endif %clean rm -rf %{buildroot} diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index c57a806..09254a5 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -43,7 +43,7 @@ CONFIGURE_FILE(dbus-1/system.d/org.tizen.vasum.host.conf.in INSTALL(FILES ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.vasum.host.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/) -INSTALL(DIRECTORY DESTINATION ${VSM_CONFIG_INSTALL_DIR}/zones) #TODO temporary solution +INSTALL(DIRECTORY DESTINATION ${DATA_DIR}/zones) INSTALL(FILES ${zone_templates_CONF} DESTINATION ${VSM_CONFIG_INSTALL_DIR}/templates) diff --git a/server/configs/templates/fedora.conf b/server/configs/templates/fedora.conf new file mode 100644 index 0000000..3ee2c06 --- /dev/null +++ b/server/configs/templates/fedora.conf @@ -0,0 +1,21 @@ +{ + "zoneTemplate" : "fedora.sh", + "initWithArgs" : [], + "requestedState" : "stopped", + "ipv4Gateway" : "", + "ipv4" : "", + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : 1000, + "privilege" : 10, + "vt" : -1, + "shutdownTimeout" : 10, + "switchToDefaultAfterTimeout" : true, + "runMountPoint" : "~NAME~/run", + "provisions" : [], + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ], + "validLinkPrefixes" : [ "/tmp/", + "/run/", + "/opt/usr/data/", + "/opt/usr/dbsapce/" ] +} diff --git a/server/configs/templates/template.sh b/server/configs/templates/template.sh index 3bcf528..ab6edf7 100755 --- a/server/configs/templates/template.sh +++ b/server/configs/templates/template.sh @@ -23,6 +23,7 @@ do done br_name="virbr-${name}" +broadcast="$(echo $ipv4|cut -d . -f -3).255" # XXX assume rootfs if mounted from iso @@ -61,10 +62,11 @@ EOF # prepare pre start hook > ${path}/pre-start.sh cat <> ${path}/pre-start.sh -if [ -z "\$(/usr/sbin/ip link show | /bin/grep -P "${br_name}:")" ] +if ! /usr/sbin/ip link show ${br_name} &>/dev/null then /usr/sbin/ip link add name ${br_name} type bridge - /sbin/ifconfig ${br_name} ${ipv4_gateway} netmask 255.255.255.0 up + /usr/sbin/ip link set ${br_name} up + /usr/sbin/ip addr add ${ipv4}/24 broadcast ${broadcast} dev ${br_name} fi if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ] then diff --git a/server/configs/templates/tizen-common-wayland.sh b/server/configs/templates/tizen-common-wayland.sh index 30b90cd..05cca6d 100755 --- a/server/configs/templates/tizen-common-wayland.sh +++ b/server/configs/templates/tizen-common-wayland.sh @@ -76,6 +76,7 @@ if [ -z "$path" ]; then fi br_name="virbr-${name}" +broadcast="$(echo $ipv4|cut -d . -f -3).255" # Prepare zone rootfs ROOTFS_DIRS="\ @@ -279,10 +280,11 @@ EOF # Prepare zone hook files cat <>${path}/hooks/pre-start.sh -if [ -z "\$(/usr/sbin/ip link show | /bin/grep -P "${br_name}:")" ] +if ! /usr/sbin/ip link show ${br_name} &>/dev/null then /usr/sbin/ip link add name ${br_name} type bridge - /sbin/ifconfig ${br_name} ${ipv4_gateway} netmask 255.255.255.0 up + /usr/sbin/ip link set ${br_name} up + /usr/sbin/ip addr add ${ipv4}/24 broadcast ${broadcast} dev ${br_name} fi if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ] then diff --git a/server/configs/templates/default.conf b/server/configs/templates/tizen.conf similarity index 100% rename from server/configs/templates/default.conf rename to server/configs/templates/tizen.conf diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index a0a0205..ace7ee4 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -1206,20 +1206,22 @@ void ZonesManager::generateNewConfig(const std::string& id, ZONE_NAME_REGEX, id); - // generate first free VT number - const int freeVT = getVTForNewZone(); - LOGD("VT number: " << freeVT); - dynamicConfig.vt = freeVT; - - // generate third IP octet for network config - std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); - LOGD("IP third octet: " << thirdOctetStr); - dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway, - ZONE_IP_THIRD_OCTET_REGEX, - thirdOctetStr); - dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4, - ZONE_IP_THIRD_OCTET_REGEX, - thirdOctetStr); + if (dynamicConfig.vt >= 0 && !dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) { + // generate first free VT number + const int freeVT = getVTForNewZone(); + LOGD("VT number: " << freeVT); + dynamicConfig.vt = freeVT; + + // generate third IP octet for network config + std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); + LOGD("IP third octet: " << thirdOctetStr); + dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); + dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); + } // save dynamic config config::saveToKVStore(mConfig.dbPath, dynamicConfig, dbPrefix); -- 2.7.4 From 6085e73704a1016f792e954b583de790afe36667 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Mon, 29 Jun 2015 16:13:12 +0200 Subject: [PATCH 10/16] Adjust to coding style rules [Feature] package includes in double quotes [Cause] n/a [Solution] replace tiangle brackets to double quotes [Verification] Build Change-Id: I7fc5815a3213566172dc8561240f463d610e48ea --- cli/command-line-interface.cpp | 2 +- client/vasum-client-impl.cpp | 9 ++++----- client/vasum-client-impl.hpp | 7 +++---- client/vasum-client.cpp | 2 +- common/lxc/zone.cpp | 3 +-- common/netlink/netlink-message.cpp | 3 +-- common/netlink/netlink.cpp | 2 +- server/netdev.cpp | 3 +-- tests/unit_tests/client/ut-client-utils.cpp | 4 ++-- tests/unit_tests/client/ut-client.cpp | 5 ++--- tests/unit_tests/ipc/ut-socket.cpp | 4 +--- tests/unit_tests/server/ut-zones-manager.cpp | 8 +++----- tests/unit_tests/socket_test_service/socket-test.cpp | 13 +++++-------- 13 files changed, 26 insertions(+), 39 deletions(-) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index 0c28cdd..a8b7d1b 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -24,7 +24,7 @@ #include "config.hpp" #include "command-line-interface.hpp" -#include +#include "vasum-client.h" #include #include diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 343fd1b..0e6e004 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -28,16 +28,15 @@ //vsm_get_poll_fd, vsm_enter_eventloop can't be used at the same time. //TODO: Make vsm_get_status_message thread-safe version (vsm_get_status_message_r) -#include +#include "config.hpp" #include "vasum-client-impl.hpp" #include "utils.hpp" #include "exception.hpp" #include "utils/exception.hpp" #include "logger/logger.hpp" - -#include -#include -#include +#include "host-ipc-definitions.hpp" +#include "ipc/client.hpp" +#include "api/messages.hpp" #include #include diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 845cf29..c949ce2 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -27,10 +27,9 @@ #define VASUM_CLIENT_IMPL_HPP #include "vasum-client.h" - -#include -#include -#include +#include "ipc/epoll/thread-dispatcher.hpp" +#include "ipc/epoll/event-poll.hpp" +#include "ipc/client.hpp" #include #include diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 4acd82a..0742cc0 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -23,7 +23,7 @@ * @brief This file contains the public API for Vasum Client */ -#include +#include "config.hpp" #include "vasum-client.h" #include "vasum-client-impl.hpp" diff --git a/common/lxc/zone.cpp b/common/lxc/zone.cpp index 845d959..65207bd 100644 --- a/common/lxc/zone.cpp +++ b/common/lxc/zone.cpp @@ -40,11 +40,10 @@ #ifdef USE_EXEC #include "utils/c-array.hpp" #endif +#include "utils/initctl.hpp" #include #include - -#include #include #include diff --git a/common/netlink/netlink-message.cpp b/common/netlink/netlink-message.cpp index c64199a..29b079a 100644 --- a/common/netlink/netlink-message.cpp +++ b/common/netlink/netlink-message.cpp @@ -26,8 +26,7 @@ #include "netlink-message.hpp" #include "netlink.hpp" #include "base-exception.hpp" - -#include +#include "logger/logger.hpp" #include #include diff --git a/common/netlink/netlink.cpp b/common/netlink/netlink.cpp index 6d7be95..b048031 100644 --- a/common/netlink/netlink.cpp +++ b/common/netlink/netlink.cpp @@ -29,8 +29,8 @@ #include "utils/make-clean.hpp" #include "utils/environment.hpp" #include "base-exception.hpp" +#include "logger/logger.hpp" -#include #include #include #include diff --git a/server/netdev.cpp b/server/netdev.cpp index b9a1389..8c53d38 100644 --- a/server/netdev.cpp +++ b/server/netdev.cpp @@ -29,8 +29,7 @@ #include "utils/exception.hpp" #include "utils.hpp" #include "exception.hpp" - -#include +#include "logger/logger.hpp" #include #include diff --git a/tests/unit_tests/client/ut-client-utils.cpp b/tests/unit_tests/client/ut-client-utils.cpp index 7a1b5ac..08d43ee 100644 --- a/tests/unit_tests/client/ut-client-utils.cpp +++ b/tests/unit_tests/client/ut-client-utils.cpp @@ -23,9 +23,9 @@ * @brief Unit tests of the client utils */ -#include +#include "config.hpp" #include "ut.hpp" -#include +#include "utils.hpp" BOOST_AUTO_TEST_SUITE(ClientUtils) diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 65d6e49..5e1f4d8 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -23,10 +23,9 @@ * @brief Unit tests of the client C API */ -#include +#include "config.hpp" #include "ut.hpp" -#include - +#include "vasum-client.h" #include "utils/latch.hpp" #include "utils/scoped-dir.hpp" #include "zones-manager.hpp" diff --git a/tests/unit_tests/ipc/ut-socket.cpp b/tests/unit_tests/ipc/ut-socket.cpp index c2577ee..1aacd22 100644 --- a/tests/unit_tests/ipc/ut-socket.cpp +++ b/tests/unit_tests/ipc/ut-socket.cpp @@ -24,10 +24,8 @@ #include "config.hpp" #include "ut.hpp" - #include "ipc/internals/socket.hpp" - -#include +#include "socket-test.hpp" using namespace ipc; diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 125d857..1fb3316 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -25,7 +25,6 @@ #include "config.hpp" #include "ut.hpp" - #include "zones-manager.hpp" #ifdef DBUS_CONNECTION // TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager @@ -36,11 +35,10 @@ #include "dbus/exception.hpp" #endif //DBUS_CONNECTION #include "host-ipc-definitions.hpp" -#include -#include -#include +#include "api/messages.hpp" +#include "ipc/epoll/thread-dispatcher.hpp" +#include "ipc/client.hpp" #include "exception.hpp" - #include "utils/glib-loop.hpp" #include "config/exception.hpp" #include "utils/latch.hpp" diff --git a/tests/unit_tests/socket_test_service/socket-test.cpp b/tests/unit_tests/socket_test_service/socket-test.cpp index 1ffc09e..841cbfd 100644 --- a/tests/unit_tests/socket_test_service/socket-test.cpp +++ b/tests/unit_tests/socket_test_service/socket-test.cpp @@ -22,15 +22,12 @@ * @brief Mini-service for IPC Socket mechanism tests */ -#include +#include "config.hpp" #include "socket-test.hpp" - -#include -#include -#include - -#include -#include +#include "logger/logger.hpp" +#include "logger/backend-journal.hpp" +#include "ipc/internals/socket.hpp" +#include "ipc/exception.hpp" #include #include -- 2.7.4 From dff76da590ee1bf8da6ae6266e8c2b796f36c639 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 22 Jun 2015 14:03:15 +0200 Subject: [PATCH 11/16] Interactive mode and other improvements to vasum-cli tool [Feature] These features have been implemented/updated: - interactive mode - persistent connection during interactive mode - better help - simple mode for cli auto-completion The interactive mode allows to make full use of queue lock/unlock commands. They can also be easily tested with it. [Cause] n/a [Solution] n/a [Verification] Run vasum-cli and executed several commands. Tested auto completion. Tested lock/unlock queue. Change-Id: If623559c9250bf480cc600ba89c2d5fe02137a18 --- cli/CMakeLists.txt | 17 ++ cli/command-line-interface.cpp | 345 +++++++++++++++++++-------------- cli/command-line-interface.hpp | 133 +++++++++---- cli/main.cpp | 323 ++++++++++++++++++++++++++---- cli/support/vasum-cli-completion.sh.in | 2 +- packaging/vasum.spec | 1 + 6 files changed, 605 insertions(+), 216 deletions(-) diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index f8ad183..36750f0 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -25,6 +25,23 @@ FILE(GLOB cli_SRCS *.cpp *.hpp) SET(CLI_CODENAME "${PROJECT_NAME}-cli") ADD_EXECUTABLE(${CLI_CODENAME} ${cli_SRCS}) +## Readline detection ########################################################## + +FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h + HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES include) +FIND_LIBRARY(READLINE_LIBRARY readline + HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES lib) +FIND_LIBRARY(NCURSES_LIBRARY ncurses) # readline depends on libncurses +MARK_AS_ADVANCED(READLINE_INCLUDE_DIR READLINE_LIBRARY NCURSES_LIBRARY) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG + READLINE_LIBRARY NCURSES_LIBRARY READLINE_INCLUDE_DIR) + +SET(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR}) +SET(READLINE_LIBRARIES ${READLINE_LIBRARY} ${NCURSES_LIBRARY}) +INCLUDE_DIRECTORIES(${READLINE_INCLUDE_DIRS}) +TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${READLINE_LIBRARIES}) ## Link libraries ############################################################## PKG_CHECK_MODULES(LIB_DEPS REQUIRED vasum) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index a8b7d1b..2b56594 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -45,43 +45,9 @@ using namespace std; namespace vasum { namespace cli { -namespace { - -/** - * Invoke specific function on VsmClient - * - * @param fun Function to be called. It must not throw any exception. - */ -void one_shot(const function& fun) -{ - string msg; - VsmStatus status; - VsmClient client; - - client = vsm_client_create(); - if (NULL == client) { - msg = "Can't create client"; - goto finish; - } - - status = vsm_connect(client); - if (VSMCLIENT_SUCCESS != status) { - msg = vsm_get_status_message(client); - goto finish; - } - - status = fun(client); - if (VSMCLIENT_SUCCESS != status) { - msg = vsm_get_status_message(client); - goto finish; - } +VsmClient CommandLineInterface::client = NULL; -finish: - vsm_client_free(client); - if (! msg.empty()) { - throw runtime_error(msg); - } -} +namespace { template string stringAsInStream(const T& value) @@ -181,11 +147,83 @@ enum macvlan_mode macvlanFromString(const std::string& mode) { } // namespace +void CommandLineInterface::connect() +{ + string msg; + VsmStatus status; + + CommandLineInterface::client = vsm_client_create(); + if (NULL == CommandLineInterface::client) { + msg = "Can't create client"; + goto finish; + } + + status = vsm_connect(client); + if (VSMCLIENT_SUCCESS != status) { + msg = vsm_get_status_message(CommandLineInterface::client); + } + +finish: + if (!msg.empty()) { + vsm_client_free(CommandLineInterface::client); + CommandLineInterface::client = NULL; + throw runtime_error(msg); + } +} + +void CommandLineInterface::disconnect() +{ + string msg; + VsmStatus status; + + status = vsm_disconnect(CommandLineInterface::client); + if (VSMCLIENT_SUCCESS != status) { + msg = vsm_get_status_message(CommandLineInterface::client); + } + + vsm_client_free(CommandLineInterface::client); + CommandLineInterface::client = NULL; + + if (!msg.empty()) { + throw runtime_error(msg); + } +} + +void CommandLineInterface::executeCallback(const function& fun) +{ + string msg; + VsmStatus status; + + status = fun(CommandLineInterface::client); + if (VSMCLIENT_SUCCESS != status) { + msg = vsm_get_status_message(CommandLineInterface::client); + } + + if (!msg.empty()) { + throw runtime_error(msg); + } +} +const std::string& CommandLineInterface::getName() const +{ + return mName; +} + +const std::string& CommandLineInterface::getDescription() const +{ + return mDescription; +} + void CommandLineInterface::printUsage(std::ostream& out) const { - out << mUsage << "\n\n" + out << mName; + for (const auto& args : mArgsSpec) { + out << " " << args.first; + } + + out << "\n\n" << "\tDescription\n" - << "\t\t" << mUsageInfo << "\n"; + << "\t\t" << mDescription << "\n"; + if (!mArgsSpec.empty()) { out << "\n\tOptions\n"; for (const auto& args : mArgsSpec) { @@ -195,90 +233,109 @@ void CommandLineInterface::printUsage(std::ostream& out) const out << "\n"; } -void CommandLineInterface::execute(int pos, int argc, const char** argv) +bool CommandLineInterface::isAvailable(unsigned int mode) const { - mExecutorCallback(pos, argc, argv); + return (mAvailability & mode) == mode; } +void CommandLineInterface::execute(const Args& argv) +{ + mExecutorCallback(argv); +} + + +void lock_queue(const Args& /*argv*/) +{ + CommandLineInterface::executeCallback(vsm_lock_queue); +} -void set_active_zone(int pos, int argc, const char** argv) +void unlock_queue(const Args& /*argv*/) +{ + CommandLineInterface::executeCallback(vsm_unlock_queue); +} + +void set_active_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_set_active_zone, _1, argv[pos + 1])); + CommandLineInterface::executeCallback(bind(vsm_set_active_zone, _1, argv[1].c_str())); } -void create_zone(int pos, int argc, const char** argv) +void create_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_create_zone, _1, argv[pos + 1], argv[pos + 2] ? argv[pos + 2] : nullptr)); + if (argv.size() >= 3 && !argv[2].empty()) { + CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), argv[2].c_str())); + } else { + CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), nullptr)); + } } -void destroy_zone(int pos, int argc, const char** argv) +void destroy_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_destroy_zone, _1, argv[pos + 1], 1)); + CommandLineInterface::executeCallback(bind(vsm_destroy_zone, _1, argv[1].c_str(), 1)); } -void shutdown_zone(int pos, int argc, const char** argv) +void shutdown_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_shutdown_zone, _1, argv[pos + 1])); + CommandLineInterface::executeCallback(bind(vsm_shutdown_zone, _1, argv[1].c_str())); } -void start_zone(int pos, int argc, const char** argv) +void start_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_start_zone, _1, argv[pos + 1])); + CommandLineInterface::executeCallback(bind(vsm_start_zone, _1, argv[1].c_str())); } -void lock_zone(int pos, int argc, const char** argv) +void lock_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_lock_zone, _1, argv[pos + 1])); + CommandLineInterface::executeCallback(bind(vsm_lock_zone, _1, argv[1].c_str())); } -void unlock_zone(int pos, int argc, const char** argv) +void unlock_zone(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_unlock_zone, _1, argv[pos + 1])); + CommandLineInterface::executeCallback(bind(vsm_unlock_zone, _1, argv[1].c_str())); } -void get_zones_status(int /* pos */, int /* argc */, const char** /* argv */) +void get_zones_status(const Args& /* argv */) { using namespace std::placeholders; @@ -286,12 +343,12 @@ void get_zones_status(int /* pos */, int /* argc */, const char** /* argv */) VsmString activeId; Table table; - one_shot(bind(vsm_get_zone_ids, _1, &ids)); - one_shot(bind(vsm_get_active_zone_id, _1, &activeId)); + CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids)); + CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &activeId)); table.push_back({"Active", "Id", "State", "Terminal", "Root"}); for (VsmString* id = ids; *id; ++id) { VsmZone zone; - one_shot(bind(vsm_lookup_zone_by_id, _1, *id, &zone)); + CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, *id, &zone)); assert(string(zone->id) == string(*id)); table.push_back({string(zone->id) == string(activeId) ? "*" : "", zone->id, @@ -305,12 +362,12 @@ void get_zones_status(int /* pos */, int /* argc */, const char** /* argv */) cout << table << endl; } -void get_zone_ids(int /* pos */, int /* argc */, const char** /* argv */) +void get_zone_ids(const Args& /*argv*/) { using namespace std::placeholders; VsmArrayString ids; - one_shot(bind(vsm_get_zone_ids, _1, &ids)); + CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids)); string delim; for (VsmString* id = ids; *id; ++id) { cout << delim << *id; @@ -320,136 +377,136 @@ void get_zone_ids(int /* pos */, int /* argc */, const char** /* argv */) vsm_array_string_free(ids); } -void get_active_zone_id(int /* pos */, int /* argc */, const char** /* argv */) +void get_active_zone_id(const Args& /*argv*/) { using namespace std::placeholders; VsmString id; - one_shot(bind(vsm_get_active_zone_id, _1, &id)); + CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &id)); cout << id << endl; vsm_string_free(id); } -void lookup_zone_by_id(int pos, int argc, const char** argv) +void lookup_zone_by_id(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } VsmZone zone; - one_shot(bind(vsm_lookup_zone_by_id, _1, argv[pos + 1], &zone)); + CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, argv[1].c_str(), &zone)); cout << zone << endl; vsm_zone_free(zone); } -void grant_device(int pos, int argc, const char** argv) +void grant_device(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } uint32_t flags = O_RDWR; - one_shot(bind(vsm_grant_device, _1, argv[pos + 1], argv[pos + 2], flags)); + CommandLineInterface::executeCallback(bind(vsm_grant_device, _1, argv[1].c_str(), argv[2].c_str(), flags)); } -void revoke_device(int pos, int argc, const char** argv) +void revoke_device(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_revoke_device, _1, argv[pos + 1], argv[pos + 2])); + CommandLineInterface::executeCallback(bind(vsm_revoke_device, _1, argv[1].c_str(), argv[2].c_str())); } -void create_netdev_veth(int pos, int argc, const char** argv) +void create_netdev_veth(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 3) { + if (argv.size() <= 3) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_create_netdev_veth, + CommandLineInterface::executeCallback(bind(vsm_create_netdev_veth, _1, - argv[pos + 1], - argv[pos + 2], - argv[pos + 3])); + argv[1].c_str(), + argv[2].c_str(), + argv[3].c_str())); } -void create_netdev_macvlan(int pos, int argc, const char** argv) +void create_netdev_macvlan(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 4) { + if (argv.size() <= 4) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_create_netdev_macvlan, + CommandLineInterface::executeCallback(bind(vsm_create_netdev_macvlan, _1, - argv[pos + 1], - argv[pos + 2], - argv[pos + 3], - macvlanFromString(argv[pos + 4]))); + argv[1].c_str(), + argv[2].c_str(), + argv[3].c_str(), + macvlanFromString(argv[4].c_str()))); } -void create_netdev_phys(int pos, int argc, const char** argv) +void create_netdev_phys(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_create_netdev_phys, + CommandLineInterface::executeCallback(bind(vsm_create_netdev_phys, _1, - argv[pos + 1], - argv[pos + 2])); + argv[1].c_str(), + argv[2].c_str())); } -void lookup_netdev_by_name(int pos, int argc, const char** argv) +void lookup_netdev_by_name(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } VsmNetdev vsmNetdev = NULL; - one_shot(bind(vsm_lookup_netdev_by_name, + CommandLineInterface::executeCallback(bind(vsm_lookup_netdev_by_name, _1, - argv[pos + 1], - argv[pos + 2], + argv[1].c_str(), + argv[2].c_str(), &vsmNetdev)); cout << vsmNetdev << endl; vsm_netdev_free(vsmNetdev); } -void destroy_netdev(int pos, int argc, const char** argv) +void destroy_netdev(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_destroy_netdev, + CommandLineInterface::executeCallback(bind(vsm_destroy_netdev, _1, - argv[pos + 1], - argv[pos + 2])); + argv[1].c_str(), + argv[2].c_str())); } -void zone_get_netdevs(int pos, int argc, const char** argv) +void zone_get_netdevs(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 1) { + if (argv.size() <= 1) { throw runtime_error("Not enough parameters"); } VsmArrayString ids; - one_shot(bind(vsm_zone_get_netdevs, + CommandLineInterface::executeCallback(bind(vsm_zone_get_netdevs, _1, - argv[pos + 1], + argv[1].c_str(), &ids)); string delim; for (VsmString* id = ids; *id; ++id) { @@ -463,18 +520,18 @@ void zone_get_netdevs(int pos, int argc, const char** argv) vsm_array_string_free(ids); } -void netdev_get_ipv4_addr(int pos, int argc, const char** argv) +void netdev_get_ipv4_addr(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } in_addr addr; - one_shot(bind(vsm_netdev_get_ipv4_addr, + CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv4_addr, _1, - argv[pos + 1], - argv[pos + 2], + argv[1].c_str(), + argv[2].c_str(), &addr)); char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) == NULL) { @@ -483,18 +540,18 @@ void netdev_get_ipv4_addr(int pos, int argc, const char** argv) cout << buf << endl; } -void netdev_get_ipv6_addr(int pos, int argc, const char** argv) +void netdev_get_ipv6_addr(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } in6_addr addr; - one_shot(bind(vsm_netdev_get_ipv6_addr, + CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv6_addr, _1, - argv[pos + 1], - argv[pos + 2], + argv[1].c_str(), + argv[2].c_str(), &addr)); char buf[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN) == NULL) { @@ -503,68 +560,68 @@ void netdev_get_ipv6_addr(int pos, int argc, const char** argv) cout << buf << endl; } -void netdev_set_ipv4_addr(int pos, int argc, const char** argv) +void netdev_set_ipv4_addr(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 4) { + if (argv.size() <= 4) { throw runtime_error("Not enough parameters"); } in_addr addr; - if (inet_pton(AF_INET, argv[pos + 3], &addr) != 1) { + if (inet_pton(AF_INET, argv[3].c_str(), &addr) != 1) { throw runtime_error("Wrong address format"); }; - one_shot(bind(vsm_netdev_set_ipv4_addr, + CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv4_addr, _1, - argv[pos + 1], - argv[pos + 2], + argv[1].c_str(), + argv[2].c_str(), &addr, - stoi(argv[pos + 4]))); + stoi(argv[4].c_str()))); } -void netdev_set_ipv6_addr(int pos, int argc, const char** argv) +void netdev_set_ipv6_addr(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 4) { + if (argv.size() <= 4) { throw runtime_error("Not enough parameters"); } in6_addr addr; - if (inet_pton(AF_INET6, argv[pos + 3], &addr) != 1) { + if (inet_pton(AF_INET6, argv[3].c_str(), &addr) != 1) { throw runtime_error("Wrong address format"); }; - one_shot(bind(vsm_netdev_set_ipv6_addr, + CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv6_addr, _1, - argv[pos + 1], - argv[pos + 2], + argv[1].c_str(), + argv[2].c_str(), &addr, - stoi(argv[pos + 4]))); + stoi(argv[4].c_str()))); } -void netdev_up(int pos, int argc, const char** argv) +void netdev_up(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_netdev_up, + CommandLineInterface::executeCallback(bind(vsm_netdev_up, _1, - argv[pos + 1], - argv[pos + 2])); + argv[1].c_str(), + argv[2].c_str())); } -void netdev_down(int pos, int argc, const char** argv) +void netdev_down(const Args& argv) { using namespace std::placeholders; - if (argc <= pos + 2) { + if (argv.size() <= 2) { throw runtime_error("Not enough parameters"); } - one_shot(bind(vsm_netdev_down, + CommandLineInterface::executeCallback(bind(vsm_netdev_down, _1, - argv[pos + 1], - argv[pos + 2])); + argv[1].c_str(), + argv[2].c_str())); } } // namespace cli diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp index 6e27c74..29282d9 100644 --- a/cli/command-line-interface.hpp +++ b/cli/command-line-interface.hpp @@ -24,6 +24,8 @@ #ifndef CLI_COMMAND_LINE_INTERFACE_HPP #define CLI_COMMAND_LINE_INTERFACE_HPP +#include + #include #include #include @@ -33,6 +35,11 @@ namespace vasum { namespace cli { +#define MODE_COMMAND_LINE (1 << 0) +#define MODE_INTERACTIVE (1 << 1) + +typedef std::vector Args; + /** * Class that implements command pattern. */ @@ -42,7 +49,7 @@ public: /** * @see CommandLineInterface::execute */ - typedef std::function ExecutorCallback; + typedef std::function ExecutorCallback; /** * @see CommandLineInterface::CommandLineInterface @@ -52,7 +59,8 @@ public: /** * Dummy constructor (for stl usage) */ - CommandLineInterface() {} + CommandLineInterface() + : mAvailability(0) {} /** * Construct command @@ -63,15 +71,48 @@ public: * @param argsSpec Description of arguments */ CommandLineInterface(const ExecutorCallback& executorCallback, - const std::string& usage, - const std::string& usageInfo, + const std::string& name, + const std::string& description, + const unsigned int& availability, const ArgsSpec& argsSpec) : mExecutorCallback(executorCallback), - mUsage(usage), - mUsageInfo(usageInfo), + mName(name), + mDescription(description), + mAvailability(availability), mArgsSpec(argsSpec) {} /** + * Set the class (static) in a connected state. + * This persistent connection to the vasum client is required + * for calls like lock/unlock queue to work. + */ + static void connect(); + + /** + * Disconnect the class from a vasum client. + */ + static void disconnect(); + + /** + * Execute a callback passing the connected VsmClient. + * + * @param fun A callback to execute + */ + static void executeCallback(const std::function& fun); + + /** + * Get the command name + */ + const std::string& getName() const; + + /** + * Get the command description + * + * @param out Output stream + */ + const std::string& getDescription() const; + + /** * Print usage to stream * * @param out Output stream @@ -79,6 +120,13 @@ public: void printUsage(std::ostream& out) const; /** + * Check if the command is available in specific mode + * + * @param mode A mode to check the command's availability in + */ + bool isAvailable(unsigned int mode) const; + + /** * Do the work * * It calls the callback passed in constructor @@ -87,13 +135,16 @@ public: * @param argc Number of elements in argv * @param argv Command line arguments */ - void execute(int pos, int argc, const char** argv); + void execute(const Args& argv); private: + static VsmClient client; + const ExecutorCallback mExecutorCallback; - const std::string mUsage; - const std::string mUsageInfo; + const std::string mName; + const std::string mDescription; + const unsigned int mAvailability; const ArgsSpec mArgsSpec; }; @@ -102,174 +153,188 @@ private: * * @see vsm_set_active_zone */ -void set_active_zone(int pos, int argc, const char** argv); +void lock_queue(const Args& argv); + +/** + * Parses command line arguments and call vsm_set_active_zone + * + * @see vsm_set_active_zone + */ +void unlock_queue(const Args& argv); + +/** + * Parses command line arguments and call vsm_set_active_zone + * + * @see vsm_set_active_zone + */ +void set_active_zone(const Args& argv); /** * Parses command line arguments and call vsm_create_zone * * @see vsm_create_zone */ -void create_zone(int pos, int argc, const char** argv); +void create_zone(const Args& argv); /** * Parses command line arguments and call vsm_destroy_zone * * @see vsm_destroy_zone */ -void destroy_zone(int pos, int argc, const char** argv); +void destroy_zone(const Args& argv); /** * Parses command line arguments and call vsm_shutdown_zone * * @see vsm_shutdown_zone */ -void shutdown_zone(int pos, int argc, const char** argv); +void shutdown_zone(const Args& argv); /** * Parses command line arguments and call vsm_start_zone * * @see vsm_start_zone */ -void start_zone(int pos, int argc, const char** argv); +void start_zone(const Args& argv); /** * Parses command line arguments and call vsm_lock_zone * * @see vsm_lock_zone */ -void lock_zone(int pos, int argc, const char** argv); +void lock_zone(const Args& argv); /** * Parses command line arguments and call vsm_unlock_zone * * @see vsm_unlock_zone */ -void unlock_zone(int pos, int argc, const char** argv); +void unlock_zone(const Args& argv); /** * Parses command line arguments and prints list of zone with * some useful informations (id, state, terminal, root path) */ -void get_zones_status(int pos, int argc, const char** argv); +void get_zones_status(const Args& argv); /** * Parses command line arguments and call vsm_get_zone_ids * * @see vsm_get_zone_ids */ -void get_zone_ids(int pos, int argc, const char** argv); +void get_zone_ids(const Args& argv); /** * Parses command line arguments and call vsm_get_active_zone_id * * @see vsm_get_active_zone_id */ -void get_active_zone_id(int pos, int argc, const char** argv); +void get_active_zone_id(const Args& argv); /** * Parses command line arguments and call vsm_lookup_zone_by_id * * @see vsm_lookup_zone_by_id */ -void lookup_zone_by_id(int pos, int argc, const char** argv); +void lookup_zone_by_id(const Args& argv); /** * Parses command line arguments and call vsm_grant_device * * @see vsm_grant_device */ -void grant_device(int pos, int argc, const char** argv); +void grant_device(const Args& argv); /** * Parses command line arguments and call vsm_revoke_device * * @see vsm_revoke_device */ -void revoke_device(int pos, int argc, const char** argv); +void revoke_device(const Args& argv); /** * Parses command line arguments and call vsm_create_netdev_veth * * @see vsm_create_netdev_veth */ -void create_netdev_veth(int pos, int argc, const char** argv); +void create_netdev_veth(const Args& argv); /** * Parses command line arguments and call vsm_create_netdev_macvlan * * @see vsm_create_netdev_macvlan */ -void create_netdev_macvlan(int pos, int argc, const char** argv); +void create_netdev_macvlan(const Args& argv); /** * Parses command line arguments and call vsm_create_netdev_phys * * @see vsm_create_netdev_phys */ -void create_netdev_phys(int pos, int argc, const char** argv); +void create_netdev_phys(const Args& argv); /** * Parses command line arguments and call vsm_lookup_netdev_by_name * * @see vsm_lookup_netdev_by_name */ -void lookup_netdev_by_name(int pos, int argc, const char** argv); +void lookup_netdev_by_name(const Args& argv); /** * Parses command line arguments and call vsm_destroy_netdev * * @see vsm_destroy_netdev */ -void destroy_netdev(int pos, int argc, const char** argv); +void destroy_netdev(const Args& argv); /** * Parses command line arguments and prints result of vsm_zone_get_netdevs * * @see vsm_zone_get_netdevs */ -void zone_get_netdevs(int pos, int argc, const char** argv); +void zone_get_netdevs(const Args& argv); /** * Parses command line arguments and prints result of vsm_netdev_get_ipv4_addr * * @see vsm_netdev_get_ipv4_addr */ -void netdev_get_ipv4_addr(int pos, int argc, const char** argv); +void netdev_get_ipv4_addr(const Args& argv); /** * Parses command line arguments and and prints result of vsm_netdev_get_ipv6_addr * * @see vsm_netdev_get_ipv6_addr */ -void netdev_get_ipv6_addr(int pos, int argc, const char** argv); +void netdev_get_ipv6_addr(const Args& argv); /** * Parses command line arguments and call vsm_netdev_set_ipv4_addr * * @see vsm_netdev_set_ipv4_addr */ -void netdev_set_ipv4_addr(int pos, int argc, const char** argv); +void netdev_set_ipv4_addr(const Args& argv); /** * Parses command line arguments and call vsm_netdev_set_ipv6_addr * * @see vsm_netdev_set_ipv6_addr */ -void netdev_set_ipv6_addr(int pos, int argc, const char** argv); +void netdev_set_ipv6_addr(const Args& argv); /** * Parses command line arguments and call vsm_netdev_up * * @see vsm_netdev_up */ -void netdev_up(int pos, int argc, const char** argv); +void netdev_up(const Args& argv); /** * Parses command line arguments and call vsm_netdev_down * * @see vsm_netdev_down */ -void netdev_down(int pos, int argc, const char** argv); +void netdev_down(const Args& argv); } // namespace cli } // namespace vasum diff --git a/cli/main.cpp b/cli/main.cpp index af36c74..dcb6891 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -30,6 +30,11 @@ #include #include #include +#include +#include +#include +#include +#include using namespace vasum::cli; @@ -37,18 +42,38 @@ namespace { std::map commands = { { + "lock_queue", { + lock_queue, + "lock_queue", + "Exclusively lock the command queue", + MODE_INTERACTIVE, + {} + } + }, + { + "unlock_queue", { + unlock_queue, + "unlock_queue", + "Unlock the queue", + MODE_INTERACTIVE, + {} + } + }, + { "set_active_zone", { set_active_zone, - "set_active_zone zone_id", + "set_active_zone", "Set active (foreground) zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "create_zone", { create_zone, - "create_zone zone_id [zone_tname]", + "create_zone", "Create and add zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"[zone_tname]", "optional zone template name"}} } @@ -56,40 +81,45 @@ std::map commands = { { "destroy_zone", { destroy_zone, - "destroy_zone zone_id", + "destroy_zone", "Destroy zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "shutdown_zone", { shutdown_zone, - "shutdown_zone zone_id", + "shutdown_zone", "Shutdown zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "start_zone", { start_zone, - "start_zone zone_id", + "start_zone", "Start zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "lock_zone", { lock_zone, - "lock_zone zone_id", + "lock_zone", "Lock zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "unlock_zone", { unlock_zone, - "unlock_zone zone_id", + "unlock_zone", "Unlock zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, @@ -98,6 +128,7 @@ std::map commands = { get_zones_status, "get_zones_status", "Get list of zone with some useful informations (id, state, terminal, root path)", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {} } }, @@ -106,6 +137,7 @@ std::map commands = { get_zone_ids, "get_zone_ids", "Get all zone ids", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {} } }, @@ -114,22 +146,25 @@ std::map commands = { get_active_zone_id, "get_active_zone_id", "Get active (foreground) zone ids", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {} } }, { "lookup_zone_by_id", { lookup_zone_by_id, - "lookup_zone_by_id zone_id", + "lookup_zone_by_id", "Prints informations about zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "grant_device", { grant_device, - "grant_device zone_id device_name", + "grant_device", "Grants access to the given device", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"device_name", " device name"}} } @@ -137,8 +172,9 @@ std::map commands = { { "revoke_device", { revoke_device, - "revoke_device zone_id device_name", + "revoke_device", "Revokes access to the given device", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"device_name", " device name"}} } @@ -146,8 +182,9 @@ std::map commands = { { "create_netdev_veth", { create_netdev_veth, - "create_netdev_veth zone_id zone_netdev_id host_netdev_id", + "create_netdev_veth", "Create netdev in zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"zone_netdev_id", "network device id"}, {"host_netdev_id", "host bridge id"}} @@ -156,8 +193,9 @@ std::map commands = { { "create_netdev_macvlan", { create_netdev_macvlan, - "create_netdev_macvlan zone_id zone_netdev_id host_netdev_id mode", + "create_netdev_macvlan", "Create netdev in zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"zone_netdev_id", "network device id"}, {"host_netdev_id", "host bridge id"}, @@ -167,8 +205,9 @@ std::map commands = { { "create_netdev_phys", { create_netdev_phys, - "create_netdev_phys zone_id netdev_id", + "create_netdev_phys", "Create/move netdev to zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}} } @@ -176,8 +215,9 @@ std::map commands = { { "lookup_netdev_by_name", { lookup_netdev_by_name, - "lookup_netdev_by_name zone_id netdev_id", + "lookup_netdev_by_name", "Get netdev flags", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}} } @@ -185,8 +225,9 @@ std::map commands = { { "destroy_netdev", { destroy_netdev, - "destroy_netdev zone_id devId", + "destroy_netdev", "Destroy netdev in zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}} } @@ -194,16 +235,18 @@ std::map commands = { { "zone_get_netdevs", { zone_get_netdevs, - "zone_get_netdevs zone_id", + "zone_get_netdevs", "List network devices in the zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}} } }, { "netdev_get_ipv4_addr", { netdev_get_ipv4_addr, - "netdev_get_ipv4_addr zone_id netdev_id", + "netdev_get_ipv4_addr", "Get ipv4 address", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}} } @@ -211,8 +254,9 @@ std::map commands = { { "netdev_get_ipv6_addr", { netdev_get_ipv6_addr, - "netdev_get_ipv6_addr zone_id netdev_id", + "netdev_get_ipv6_addr", "Get ipv6 address", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}} } @@ -220,8 +264,9 @@ std::map commands = { { "netdev_set_ipv4_addr", { netdev_set_ipv4_addr, - "netdev_set_ipv4_addr zone_id netdev_id address prefix_len", + "netdev_set_ipv4_addr", "Set ipv4 address", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}, {"address", "ipv4 address"}, @@ -231,8 +276,9 @@ std::map commands = { { "netdev_set_ipv6_addr", { netdev_set_ipv6_addr, - "netdev_set_ipv6_addr zone_id netdev_id address prefix_len", + "netdev_set_ipv6_addr", "Set ipv6 address", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device name"}, {"address", "ipv6 address"}, @@ -242,8 +288,9 @@ std::map commands = { { "netdev_up", { netdev_up, - "netdev_up zone_id netdev_id", + "netdev_up", "Turn up a network device in the zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device id"}} } @@ -251,8 +298,9 @@ std::map commands = { { "netdev_down", { netdev_down, - "netdev_down zone_id netdev_id", + "netdev_down", "Turn down a network device in the zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device id"}} } @@ -260,50 +308,251 @@ std::map commands = { { "zone_get_netdevs", { zone_get_netdevs, - "zone_get_netdevs zone_id", + "zone_get_netdevs", "Turn down a network device in the zone", + MODE_COMMAND_LINE | MODE_INTERACTIVE, {{"zone_id", "id zone name"}, {"netdev_id", "network device id"}} } } }; -void printUsage(std::ostream& out, const std::string& name) +// wrappers for CommandLineInterface + +void printUsage(std::ostream& out, const std::string& name, unsigned int mode) { - out << "Usage: " << name << " [command [-h|args]]\n\n" - << "command can be one of the following:\n"; + std::string n; + if (!name.empty()) { + n = name + " "; + } + + out << "Usage: " << n << "[] [-h|]\n\n"; + if (mode == MODE_COMMAND_LINE) { + out << "Called without parameters enters interactive mode.\n\n"; + } + out << "command can be one of the following:\n"; for (const auto& command : commands) { - command.second.printUsage(out); + if (command.second.isAvailable(mode)) { + out << " " << std::setw(30) << std::left << command.second.getName() + << command.second.getDescription() << "\n"; + } } + + out << "\nSee " << n << "command -h to read about a specific one.\n"; } -} // namespace +int connect() +{ + try { + CommandLineInterface::connect(); + } catch (const std::runtime_error& ex) { + std::cerr << ex.what() << std::endl; + return EXIT_FAILURE; + } -int main(const int argc, const char** argv) + return EXIT_SUCCESS; +} + +int disconnect() { - if (argc < 2) { - printUsage(std::cout, argv[0]); + try { + CommandLineInterface::disconnect(); + } catch (const std::runtime_error& ex) { + std::cerr << ex.what() << std::endl; return EXIT_FAILURE; } - if (commands.count(argv[1]) == 0) { - printUsage(std::cout, argv[0]); + + return EXIT_SUCCESS; +} + +int executeCommand(const Args& argv, int mode) +{ + auto pair = commands.find(argv[0]); + if (pair == commands.end()) { + return EXIT_FAILURE; + } + + CommandLineInterface& command = pair->second; + if (!command.isAvailable(mode)) { return EXIT_FAILURE; } - CommandLineInterface& command = commands[argv[1]]; - auto it = std::find(argv, argv+argc, std::string("-h")); - if (it != argv + argc) { + auto it = std::find(argv.begin(), argv.end(), std::string("-h")); + if (it != argv.end()) { command.printUsage(std::cout); return EXIT_SUCCESS; } try { - command.execute(1, argc, argv); + command.execute(argv); } catch (const std::runtime_error& ex) { std::cerr << ex.what() << std::endl; return EXIT_FAILURE; } + + return EXIT_SUCCESS; +} + +// readline completion support + +char* object_generator(const char* text, int state) +{ + static std::vector objs; + static size_t len = 0, index = 0; + + if (state == 0) { + objs.clear(); + len = ::strlen(text); + index = 0; + + using namespace std::placeholders; + VsmArrayString ids = NULL; + try { + CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids)); + } catch (const std::runtime_error& ex) { + // Quietly ignore, nothing we can do anyway + } + + if (ids != NULL) { + for (VsmString* id = ids; *id; ++id) { + if (::strncmp(text, *id, len) == 0) { + objs.push_back(*id); + } + } + + vsm_array_string_free(ids); + } + } + + if (index < objs.size()) { + return ::strdup(objs[index++].c_str()); + } + + return NULL; +} + +char* cmd_generator(const char* text, int state) +{ + static std::vector cmds; + static size_t len = 0, index = 0; + + if (state == 0) { + cmds.clear(); + len = ::strlen(text); + index = 0; + + for (const auto& command : commands) { + if (command.second.isAvailable(MODE_INTERACTIVE)) { + const std::string& cmd = command.second.getName(); + if (::strncmp(text, cmd.c_str(), len) == 0) { + cmds.push_back(cmd); + } + } + } + } + + if (index < cmds.size()) { + return ::strdup(cmds[index++].c_str()); + } + + return NULL; +} + +char** completion(const char* text, int start, int /*end*/) +{ + char **matches = NULL; + + if (start == 0) { + matches = ::rl_completion_matches(text, &cmd_generator); + } else { + matches = ::rl_completion_matches(text, &object_generator); + } + + return matches; +} + +// handlers for the modes + +int interactiveMode() +{ + if (connect() != EXIT_SUCCESS) + return EXIT_FAILURE; + + ::rl_attempted_completion_function = completion; + + for (;;) { + char *line = ::readline(">>> "); + + if (line == NULL) { + break; + } + if (line[0] == '\0') { + free(line); + continue; + } + + std::istringstream iss(line); + Args argv{std::istream_iterator{iss}, + std::istream_iterator{}}; + + if (commands.count(argv[0]) == 0) { + printUsage(std::cout, "", MODE_INTERACTIVE); + free(line); + continue; + } + + executeCommand(argv, MODE_INTERACTIVE); + ::add_history(line); + free(line); + } + + disconnect(); return EXIT_SUCCESS; } +int bashComplMode() +{ + for (const auto& command : commands) { + if (command.second.isAvailable(MODE_COMMAND_LINE)) { + std::cout << command.second.getName() << "\n"; + } + } + + return EXIT_SUCCESS; +} + +int cliMode(const int argc, const char** argv) +{ + if (commands.count(argv[1]) == 0) { + printUsage(std::cout, argv[0], MODE_COMMAND_LINE); + return EXIT_FAILURE; + } + + if (connect() != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + // pass all the arguments excluding argv[0] - the executable name + Args commandArgs(argv+1, argv+argc); + int rc = executeCommand(commandArgs, MODE_COMMAND_LINE); + + disconnect(); + return rc; +} + +} // namespace + + +int main(const int argc, const char** argv) +{ + if (argc == 1) { + return interactiveMode(); + } + + if (std::string(argv[1]) == "--bash-completion") { + return bashComplMode(); + } + + return cliMode(argc, argv); +} diff --git a/cli/support/vasum-cli-completion.sh.in b/cli/support/vasum-cli-completion.sh.in index 18dda54..e04b56f 100755 --- a/cli/support/vasum-cli-completion.sh.in +++ b/cli/support/vasum-cli-completion.sh.in @@ -6,7 +6,7 @@ __@PROJECT_NAME@_cli() { COMPREPLY=() if [ "$COMP_CWORD" == "1" ]; then - COMPREPLY=($(compgen -W "$(@CLI_CODENAME@ | grep --color=never -e '^\S' | tail -n +3 | cut -f1 -d' ')" -- $cur)) + COMPREPLY=($(compgen -W "$(@CLI_CODENAME@ --bash-completion)" -- $cur)) elif [ "$COMP_CWORD" == "2" ]; then COMPREPLY=($(compgen -W "-h" -- $cur)) fi diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 13112b5..acb7ada 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -23,6 +23,7 @@ BuildRequires: cmake BuildRequires: boost-devel BuildRequires: pkgconfig(glib-2.0) BuildRequires: lxc-devel +BuildRequires: readline-devel Requires: lxc %if %{platform_type} == "TIZEN" Requires: iproute2 -- 2.7.4 From 1d03f8b33c430d889d0b3dcdb2af8363e006985a Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 6 Jul 2015 11:41:16 +0200 Subject: [PATCH 12/16] Fix doxygen comment [Bug] Can't compile with clang 3.6 [Cause] Bad format of doxygen comment (command-line-interface.hpp) [Solution] N/A [Verification] Compile with clang. Change-Id: If8a394d67ac37f402802a23bdf990f1ea70306d2 --- cli/command-line-interface.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp index 29282d9..fe47929 100644 --- a/cli/command-line-interface.hpp +++ b/cli/command-line-interface.hpp @@ -66,9 +66,11 @@ public: * Construct command * * @param executorCallback Callback function that will do the job - * @param usage Description of use - * @param usageInfo Description of the command + * @param name Command name + * @param description Command Description + * @param availability Command availability (bit field) * @param argsSpec Description of arguments + * @remark Possible bits for availability: MODE_COMMAND_LINE, MODE_INTERACTIVE */ CommandLineInterface(const ExecutorCallback& executorCallback, const std::string& name, @@ -107,8 +109,6 @@ public: /** * Get the command description - * - * @param out Output stream */ const std::string& getDescription() const; @@ -131,8 +131,6 @@ public: * * It calls the callback passed in constructor * - * @param pos Points to element in argv where command was recognized (i.e. command name) - * @param argc Number of elements in argv * @param argv Command line arguments */ void execute(const Args& argv); -- 2.7.4 From f37af1be3f059b44cc41bdcf206d2e54ed5a9870 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 6 Jul 2015 15:25:25 +0200 Subject: [PATCH 13/16] Fix method signature (add override) [Bug] Can't compile with clang 3.6 [Cause] Missing override in method signature [Solution] N/A [Verification] Compile with clang. Change-Id: Iac6094321be0571ccb39bebc3e911665abd9053e --- common/api/dbus-method-result-builder.hpp | 2 +- common/api/ipc-method-result-builder.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/api/dbus-method-result-builder.hpp b/common/api/dbus-method-result-builder.hpp index 7673b65..b6bfa85 100644 --- a/common/api/dbus-method-result-builder.hpp +++ b/common/api/dbus-method-result-builder.hpp @@ -51,7 +51,7 @@ private: void setImpl(const std::shared_ptr& data) override; void setVoid() override; void setError(const std::string& name, const std::string& message) override; - std::string getID() const; + std::string getID() const override; ::dbus::MethodResultBuilder::Pointer mMethodResultBuilderPtr; std::function)> mSerialize; diff --git a/common/api/ipc-method-result-builder.hpp b/common/api/ipc-method-result-builder.hpp index 0b0ddd3..e9554d0 100644 --- a/common/api/ipc-method-result-builder.hpp +++ b/common/api/ipc-method-result-builder.hpp @@ -47,7 +47,7 @@ private: void setImpl(const std::shared_ptr& data) override; void setVoid() override; void setError(const std::string& name, const std::string& message) override; - std::string getID() const; + std::string getID() const override; ipc::MethodResult::Pointer mMethodResultPtr; }; -- 2.7.4 From 5c0431b218f6cf6aff9fcf2767268725cef3c2ef Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Mon, 6 Jul 2015 11:58:10 +0200 Subject: [PATCH 14/16] Moved dispatching to Server [Feature] Dispatcher can be used outside IPC. [Cause] Will be needed to process signalfd [Solution] N/A [Verification] Build, install, run tests Change-Id: I17298da5e4758bbf0fa266bcf896f464df29c9a3 --- server/host-ipc-connection.cpp | 4 +-- server/host-ipc-connection.hpp | 5 ++- server/server.cpp | 2 +- server/server.hpp | 2 ++ server/zones-manager.cpp | 4 +-- server/zones-manager.hpp | 3 +- tests/unit_tests/client/ut-client.cpp | 4 ++- tests/unit_tests/server/ut-server.cpp | 3 +- tests/unit_tests/server/ut-zones-manager.cpp | 54 ++++++++++++++-------------- 9 files changed, 43 insertions(+), 38 deletions(-) diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index f110999..e881d2f 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -35,7 +35,7 @@ namespace vasum { -HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) +HostIPCConnection::HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesManager* zonesManagerPtr) : mZonesManagerPtr(zonesManagerPtr) { LOGT("Connecting to host IPC socket"); @@ -45,7 +45,7 @@ HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) std::string id = api::IPC_CONNECTION_PREFIX + std::to_string(peerID); mZonesManagerPtr->disconnectedCallback(id); }; - mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET, + mService.reset(new ipc::Service(eventPoll, HOST_IPC_SOCKET, nullptr, removedCallback)); using namespace std::placeholders; diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index 28e3725..dcadc4a 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -27,7 +27,7 @@ #define SERVER_HOST_IPC_CONNECTION_HPP #include "api/messages.hpp" -#include "ipc/epoll/thread-dispatcher.hpp" +#include "ipc/epoll/event-poll.hpp" #include "ipc/service.hpp" #include "ipc-callback-wrapper.hpp" @@ -48,7 +48,7 @@ public: typedef typename IPCSignalWrapper::type type; }; - HostIPCConnection(ZonesManager* zm); + HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesManager* zm); ~HostIPCConnection(); void start(); @@ -90,7 +90,6 @@ private: api::FileMoveRequestStatus>::type& callback); void setCreateFileCallback(const Method::type& callback); - ipc::epoll::ThreadDispatcher mDispatcher; std::unique_ptr mService; ZonesManager* mZonesManagerPtr; }; diff --git a/server/server.cpp b/server/server.cpp index 1f749cc..5abd430 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -118,7 +118,7 @@ void Server::run(bool asRoot) LOGI("Starting daemon..."); { utils::ScopedGlibLoop loop; - ZonesManager manager(mConfigPath); + ZonesManager manager(mDispatcher.getPoll(), mConfigPath); // Do not restore zones state at Vasum start // manager.restoreAll(); diff --git a/server/server.hpp b/server/server.hpp index e034e0f..bf2519b 100644 --- a/server/server.hpp +++ b/server/server.hpp @@ -27,6 +27,7 @@ #define SERVER_SERVER_HPP #include "utils/latch.hpp" +#include "ipc/epoll/thread-dispatcher.hpp" #include @@ -61,6 +62,7 @@ public: private: std::string mConfigPath; + ipc::epoll::ThreadDispatcher mDispatcher; /** * Set needed caps, groups and drop root privileges. diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index ace7ee4..98b5a1e 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -112,9 +112,9 @@ bool zoneIsRunning(const std::unique_ptr& zone) { } // namespace -ZonesManager::ZonesManager(const std::string& configPath) +ZonesManager::ZonesManager(ipc::epoll::EventPoll& eventPoll, const std::string& configPath) : mWorker(utils::Worker::create()) - , mHostIPCConnection(this) + , mHostIPCConnection(eventPoll, this) , mDetachOnExit(false) , mExclusiveIDLock(INVALID_CONNECTION_ID) #ifdef DBUS_CONNECTION diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index e7b6675..75f83a7 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -34,6 +34,7 @@ #include "api/method-result-builder.hpp" #include "host-ipc-connection.hpp" +#include "ipc/epoll/event-poll.hpp" #ifdef DBUS_CONNECTION #include "host-dbus-connection.hpp" #include "proxy-call-policy.hpp" @@ -50,7 +51,7 @@ const std::string INVALID_CONNECTION_ID = "invalid://"; class ZonesManager final { public: - ZonesManager(const std::string& managerConfigPath); + ZonesManager(ipc::epoll::EventPoll& eventPoll, const std::string& managerConfigPath); ~ZonesManager(); /** diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 5e1f4d8..2fea841 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -31,6 +31,7 @@ #include "zones-manager.hpp" #include "host-ipc-connection.hpp" #include "host-ipc-definitions.hpp" +#include "ipc/epoll/thread-dispatcher.hpp" #include "logger/logger.hpp" #ifdef DBUS_CONNECTION @@ -61,6 +62,7 @@ const int EVENT_TIMEOUT = 500; // ms struct Fixture { utils::ScopedDir mZonesPathGuard; utils::ScopedDir mRunGuard; + ipc::epoll::ThreadDispatcher mDispatcher; #ifdef DBUS_CONNECTION utils::ScopedGlibLoop mLoop; #endif //DBUS_CONNECTION @@ -70,7 +72,7 @@ struct Fixture { Fixture() : mZonesPathGuard(ZONES_PATH) , mRunGuard("/tmp/ut-run") - , cm(new ZonesManager(TEST_CONFIG_PATH)) + , cm(new ZonesManager(mDispatcher.getPoll(), TEST_CONFIG_PATH)) { cm->createZone("zone1", TEMPLATE_NAME); cm->createZone("zone2", TEMPLATE_NAME); diff --git a/tests/unit_tests/server/ut-server.cpp b/tests/unit_tests/server/ut-server.cpp index af6d5ca..6f21872 100644 --- a/tests/unit_tests/server/ut-server.cpp +++ b/tests/unit_tests/server/ut-server.cpp @@ -54,6 +54,7 @@ const bool AS_ROOT = true; struct Fixture { utils::ScopedDir mZonesPathGuard; + ipc::epoll::ThreadDispatcher mDispatcher; Fixture() : mZonesPathGuard(ZONES_PATH) @@ -65,7 +66,7 @@ struct Fixture { void prepare() { ScopedGlibLoop loop; - ZonesManager manager(TEST_CONFIG_PATH); + ZonesManager manager(mDispatcher.getPoll(), TEST_CONFIG_PATH); manager.createZone("zone1", TEMPLATE_NAME); manager.createZone("zone2", TEMPLATE_NAME); manager.restoreAll(); diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 1fb3316..cd402b8 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -655,7 +655,7 @@ bool spinWaitFor(int timeoutMs, Predicate pred) struct Fixture { ScopedGlibLoop mLoop; - + ipc::epoll::ThreadDispatcher dispatcher; ScopedDir mZonesPathGuard; ScopedDir mRunGuard; @@ -687,27 +687,27 @@ BOOST_FIXTURE_TEST_SUITE(ZonesManagerSuite, Fixture) BOOST_AUTO_TEST_CASE(ConstructorDestructor) { std::unique_ptr cm; - cm.reset(new ZonesManager(TEST_CONFIG_PATH)); + cm.reset(new ZonesManager(dispatcher.getPoll(), TEST_CONFIG_PATH)); cm.reset(); } BOOST_AUTO_TEST_CASE(MissingConfig) { - BOOST_REQUIRE_EXCEPTION(ZonesManager{MISSING_CONFIG_PATH}, + BOOST_REQUIRE_EXCEPTION((ZonesManager(dispatcher.getPoll(), MISSING_CONFIG_PATH)), ConfigException, WhatEquals("Could not load " + MISSING_CONFIG_PATH)); } BOOST_AUTO_TEST_CASE(Create) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); } BOOST_AUTO_TEST_CASE(StartStop) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); @@ -720,7 +720,7 @@ BOOST_AUTO_TEST_CASE(StartStop) BOOST_AUTO_TEST_CASE(DetachOnExit) { { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.restoreAll(); @@ -728,7 +728,7 @@ BOOST_AUTO_TEST_CASE(DetachOnExit) cm.setZonesDetachOnExit(); } { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.restoreAll(); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1"); } @@ -736,7 +736,7 @@ BOOST_AUTO_TEST_CASE(DetachOnExit) BOOST_AUTO_TEST_CASE(Focus) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -754,7 +754,7 @@ BOOST_AUTO_TEST_CASE(Focus) #ifdef ZONE_CONNECTION BOOST_AUTO_TEST_CASE(NotifyActiveZone) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -810,7 +810,7 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZone) BOOST_AUTO_TEST_CASE(MoveFile) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -898,7 +898,7 @@ BOOST_AUTO_TEST_CASE(MoveFile) MULTI_FIXTURE_TEST_CASE(SwitchToDefault, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -921,7 +921,7 @@ MULTI_FIXTURE_TEST_CASE(SwitchToDefault, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(AllowSwitchToDefault, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -955,7 +955,7 @@ MULTI_FIXTURE_TEST_CASE(AllowSwitchToDefault, F, ACCESSORS) #ifdef DBUS_CONNECTION MULTI_FIXTURE_TEST_CASE(ProxyCall, F, DbusFixture) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -1008,7 +1008,7 @@ const std::set EXPECTED_CONNECTIONS_NONE = { "zone1", "zone2", "zon MULTI_FIXTURE_TEST_CASE(GetZoneIds, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -1025,7 +1025,7 @@ MULTI_FIXTURE_TEST_CASE(GetZoneIds, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(GetActiveZoneId, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -1048,7 +1048,7 @@ MULTI_FIXTURE_TEST_CASE(GetActiveZoneId, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(SetActiveZone, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -1081,7 +1081,7 @@ MULTI_FIXTURE_TEST_CASE(CreateDestroyZone, F, ACCESSORS) const std::string zone2 = "test2"; const std::string zone3 = "test3"; - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.restoreAll(); BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), ""); @@ -1136,8 +1136,8 @@ MULTI_FIXTURE_TEST_CASE(CreateDestroyZonePersistence, F, ACCESSORS) callDone.set(); }; - auto getZoneIds = []() -> std::vector { - ZonesManager cm(TEST_CONFIG_PATH); + auto getZoneIds = [this]() -> std::vector { + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.restoreAll(); typename F::HostAccessory host; @@ -1148,7 +1148,7 @@ MULTI_FIXTURE_TEST_CASE(CreateDestroyZonePersistence, F, ACCESSORS) // create zone { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); typename F::HostAccessory host; host.callAsyncMethodCreateZone(zone, SIMPLE_TEMPLATE, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); @@ -1162,7 +1162,7 @@ MULTI_FIXTURE_TEST_CASE(CreateDestroyZonePersistence, F, ACCESSORS) // destroy zone { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); typename F::HostAccessory host; host.callAsyncMethodDestroyZone(zone, resultCallback); BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); @@ -1186,7 +1186,7 @@ MULTI_FIXTURE_TEST_CASE(ZoneStatePersistence, F, ACCESSORS) // firts run { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); typename F::HostAccessory host; // zone1 - created @@ -1231,7 +1231,7 @@ MULTI_FIXTURE_TEST_CASE(ZoneStatePersistence, F, ACCESSORS) // second run { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.restoreAll(); BOOST_CHECK(cm.isRunning(zone1)); // because the default json value @@ -1247,7 +1247,7 @@ MULTI_FIXTURE_TEST_CASE(StartShutdownZone, F, ACCESSORS) const std::string zone1 = "zone1"; const std::string zone2 = "zone2"; - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone(zone1, SIMPLE_TEMPLATE); cm.createZone(zone2, SIMPLE_TEMPLATE); @@ -1284,7 +1284,7 @@ MULTI_FIXTURE_TEST_CASE(StartShutdownZone, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(LockUnlockZone, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.createZone("zone2", SIMPLE_TEMPLATE); cm.createZone("zone3", SIMPLE_TEMPLATE); @@ -1330,7 +1330,7 @@ MULTI_FIXTURE_TEST_CASE(LockUnlockZone, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(CreateFile, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.restoreAll(); @@ -1350,7 +1350,7 @@ MULTI_FIXTURE_TEST_CASE(CreateFile, F, ACCESSORS) MULTI_FIXTURE_TEST_CASE(CreateWriteReadFile, F, ACCESSORS) { - ZonesManager cm(TEST_CONFIG_PATH); + ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); cm.createZone("zone1", SIMPLE_TEMPLATE); cm.restoreAll(); -- 2.7.4 From 0e8e1d18c8b1c1e39864444803189d7b9591ca75 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Mon, 6 Jul 2015 10:39:24 +0200 Subject: [PATCH 15/16] Removed unused code (ZONE_CONNECTION macro) [Bug] Unused code [Cause] There is no connection to zone [Solution] Remove ZONE_CONNECTION macro and related code [Verification] Build Change-Id: I805372a08ddd3507cbe6bfaeeca968560eb593e6 --- client/vasum-client-impl.cpp | 33 --- client/vasum-client-impl.hpp | 33 --- client/vasum-client.cpp | 26 --- client/vasum-client.h | 68 ------- common/api/messages.hpp | 16 -- server/configs/templates/fedora.conf | 2 - server/configs/templates/tizen.conf | 2 - server/host-dbus-connection.cpp | 30 --- server/host-dbus-connection.hpp | 5 - server/host-dbus-definitions.hpp | 26 --- server/host-ipc-connection.cpp | 30 --- server/host-ipc-connection.hpp | 4 - server/host-ipc-definitions.hpp | 11 - server/zone-config.hpp | 14 -- server/zone.cpp | 17 -- server/zone.hpp | 14 -- server/zones-manager.cpp | 150 -------------- server/zones-manager.hpp | 8 - tests/unit_tests/client/ut-client.cpp | 72 ------- tests/unit_tests/configs/templates/buggy-init.conf | 2 - .../configs/templates/buggy-template.conf | 2 - .../configs/templates/console-dbus.conf.in | 2 - .../configs/templates/console-ipc.conf.in | 2 - tests/unit_tests/configs/templates/default.conf | 2 - tests/unit_tests/configs/templates/missing.conf | 2 - .../configs/templates/test-no-shutdown.conf | 2 - tests/unit_tests/server/ut-zones-manager.cpp | 222 --------------------- 27 files changed, 797 deletions(-) diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 0e6e004..d99b08b 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -882,36 +882,3 @@ VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) }); } -VsmStatus Client::vsm_notify_active_zone(const char* /*application*/, const char* /*message*/) noexcept -{ - return coverException([&] { - //TODO: Implement vsm_notify_active_zone - throw OperationFailedException("Not implemented"); - }); -} - -VsmStatus Client::vsm_file_move_request(const char* /*destZone*/, const char* /*path*/) noexcept -{ - return coverException([&] { - //TODO: Implement vsm_file_move_request - throw OperationFailedException("Not implemented"); - }); -} - -VsmStatus Client::vsm_add_notification_callback(VsmNotificationFunction /*notificationCallback*/, - void* /*data*/, - VsmSubscriptionId* /*subscriptionId*/) noexcept -{ - return coverException([&] { - //TODO: Implement vsm_add_notification_callback - throw OperationFailedException("Not implemented"); - }); -} - -VsmStatus Client::vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept -{ - return coverException([&] { - mClient->removeMethod(subscriptionId); - }); -} - diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index c949ce2..57797c2 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -46,17 +46,6 @@ typedef std::function VsmZoneDbusStateFunction; /** - * Notification callback function signature. - * - * @param[in] zone source zone - * @param[in] application sending application name - * @param[in] message notification message - * @param data custom user's data pointer passed to vsm_add_notification_callback() - */ -typedef std::function - VsmNotificationFunction; - -/** * vasum's client definition. * * Client uses dbus API. @@ -351,28 +340,6 @@ public: */ VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration) noexcept; - /** - * @see ::vsm_notify_active_zone - */ - VsmStatus vsm_notify_active_zone(const char* application, const char* message) noexcept; - - /** - * @see ::vsm_file_move_request - */ - VsmStatus vsm_file_move_request(const char* destZone, const char* path) noexcept; - - /** - * @see ::vsm_add_notification_callback - */ - VsmStatus vsm_add_notification_callback(VsmNotificationFunction notificationCallback, - void* data, - VsmSubscriptionId* subscriptionId) noexcept; - - /** - * @see ::vsm_del_notification_callback - */ - VsmStatus vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept; - private: struct Status { Status(); diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index 0742cc0..ac77187 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -390,29 +390,3 @@ API VsmStatus vsm_remove_declaration(VsmClient client, return getClient(client).vsm_remove_declaration(zone, declaration); } -API VsmStatus vsm_notify_active_zone(VsmClient client, - const char* application, - const char* message) -{ - return getClient(client).vsm_notify_active_zone(application, message); -} - -API VsmStatus vsm_file_move_request(VsmClient client, const char* destZone, const char* path) -{ - return getClient(client).vsm_file_move_request(destZone, path); -} - -API VsmStatus vsm_add_notification_callback(VsmClient client, - VsmNotificationCallback notificationCallback, - void* data, - VsmSubscriptionId* subscriptionId) -{ - return getClient(client).vsm_add_notification_callback(notificationCallback, data, subscriptionId); -} - -API VsmStatus vsm_del_notification_callback(VsmClient client, - VsmSubscriptionId subscriptionId) -{ - return getClient(client).vsm_del_notification_callback(subscriptionId); -} - diff --git a/client/vasum-client.h b/client/vasum-client.h index 9216ce9..4544893 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -895,76 +895,8 @@ VsmStatus vsm_remove_declaration(VsmClient client, /** @} Host API */ -/** - * @name Zone API - * - * Functions using org.tizen.vasum.zone.manager D-Bus interface. - * - * @{ - */ - -/** - * Notification callback function signature. - * - * @param[in] zone source zone - * @param[in] application sending application name - * @param[in] message notification message - * @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); -/** - * Send message to active zone. - * - * @param[in] client vasum-server's client - * @param[in] application application name - * @param[in] message message - * @return status of this function call - */ -VsmStatus vsm_notify_active_zone(VsmClient client, const char* application, const char* message); - -/** - * Move file between zones. - * - * @param[in] client vasum-server's client - * @param[in] destZone destination zone id - * @param[in] path path to moved file - * @return status of this function call - */ -VsmStatus vsm_file_move_request(VsmClient client, const char* destZone, const char* path); - -/** - * Register notification callback function. - * - * @note The callback function will be invoked on a different thread. - * - * @param[in] client vasum-server's client - * @param[in] notificationCallback callback function - * @param[in] data some extra data that will be passed to callback function - * @param[out] subscriptionId subscription identifier that can be used to unsubscribe signal, - * pointer can be NULL. - * @return status of this function call - */ -VsmStatus vsm_add_notification_callback(VsmClient client, - VsmNotificationCallback notificationCallback, - void* data, - VsmSubscriptionId* subscriptionId); - -/** - * Unregister notification callback function. - * - * @param[in] client vasum-server's client - * @param[in] subscriptionId subscription identifier returned by vsm_add_notification_callback - * @return status of this function call - */ -VsmStatus vsm_del_notification_callback(VsmClient client, VsmSubscriptionId subscriptionId); - #endif /* __VASUM_WRAPPER_SOURCE__ */ -/** @} Zone API */ - #ifdef __cplusplus } #endif diff --git a/common/api/messages.hpp b/common/api/messages.hpp index 7299898..ba6ab26 100644 --- a/common/api/messages.hpp +++ b/common/api/messages.hpp @@ -77,7 +77,6 @@ struct VectorOfStringPairs { typedef api::String ZoneId; typedef api::String Declaration; -typedef api::String FileMoveRequestStatus; typedef api::StringPair GetNetDevAttrsIn; typedef api::StringPair CreateNetDevPhysIn; typedef api::StringPair RemoveDeclarationIn; @@ -85,8 +84,6 @@ typedef api::StringPair CreateZoneIn; typedef api::StringPair RevokeDeviceIn; typedef api::StringPair DestroyNetDevIn; typedef api::StringPair ConnectionState; -typedef api::StringPair NotifActiveZoneIn; -typedef api::StringPair FileMoveRequestIn; typedef api::VectorOfStrings ZoneIds; typedef api::VectorOfStrings Declarations; typedef api::VectorOfStrings NetDevList; @@ -246,19 +243,6 @@ struct CreateFileOut { ) }; -struct Notification { - std::string zone; - std::string application; - std::string message; - - CONFIG_REGISTER - ( - zone, - application, - message - ) -}; - } // namespace api } // namespace vasum diff --git a/server/configs/templates/fedora.conf b/server/configs/templates/fedora.conf index 3ee2c06..12e0d2a 100644 --- a/server/configs/templates/fedora.conf +++ b/server/configs/templates/fedora.conf @@ -12,8 +12,6 @@ "switchToDefaultAfterTimeout" : true, "runMountPoint" : "~NAME~/run", "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [ "/tmp/", "/run/", "/opt/usr/data/", diff --git a/server/configs/templates/tizen.conf b/server/configs/templates/tizen.conf index b8eb5d5..b461ec1 100644 --- a/server/configs/templates/tizen.conf +++ b/server/configs/templates/tizen.conf @@ -12,8 +12,6 @@ "switchToDefaultAfterTimeout" : true, "runMountPoint" : "~NAME~/run", "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [ "/tmp/", "/run/", "/opt/usr/data/", diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index 20cffd9..53fc271 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -391,24 +391,6 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, return; } - if (methodName == api::dbus::METHOD_NOTIFY_ACTIVE_ZONE) { - api::NotifActiveZoneIn data; - config::loadFromGVariant(parameters, data); - - auto rb = std::make_shared>(result); - mZonesManagerPtr->handleNotifyActiveZoneCall(EMPTY_CALLER, data, rb); - return; - } - - if (methodName == api::dbus::METHOD_FILE_MOVE_REQUEST) { - api::FileMoveRequestIn data; - config::loadFromGVariant(parameters, data); - - auto rb = std::make_shared>(result); - mZonesManagerPtr->handleFileMoveCall(EMPTY_CALLER, data, rb); - return; - } - if (methodName == api::dbus::METHOD_CREATE_FILE) { api::CreateFileIn data; config::loadFromGVariant(parameters, data); @@ -458,16 +440,4 @@ void HostDbusConnection::proxyCallAsync(const std::string& busName, callback); } -void HostDbusConnection::sendNotification(const api::Notification& notify) -{ - GVariant* parameters = g_variant_new("(sss)", - notify.zone.c_str(), - notify.application.c_str(), - notify.message.c_str()); - mDbusConnection->emitSignal(api::dbus::OBJECT_PATH, - api::dbus::INTERFACE, - api::dbus::SIGNAL_NOTIFICATION, - parameters); -} - } // namespace vasum diff --git a/server/host-dbus-connection.hpp b/server/host-dbus-connection.hpp index 2b4d2a3..bb59afc 100644 --- a/server/host-dbus-connection.hpp +++ b/server/host-dbus-connection.hpp @@ -64,11 +64,6 @@ public: void setProxyCallCallback(const ProxyCallCallback& callback); /** - * Send notification signal to this zone - */ - void sendNotification(const api::Notification& notify); - - /** * Make a proxy call */ void proxyCallAsync(const std::string& busName, diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index caa333b..7aeaf31 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -67,18 +67,6 @@ const std::string METHOD_LOCK_QUEUE = "LockQueue"; const std::string METHOD_UNLOCK_QUEUE = "UnlockQueue"; const std::string METHOD_SWITCH_TO_DEFAULT = "SwitchToDefault"; -const std::string METHOD_NOTIFY_ACTIVE_ZONE = "NotifyActiveZone"; -const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest"; -const std::string SIGNAL_NOTIFICATION = "Notification"; - -const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND"; -const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION"; -const std::string FILE_MOVE_NO_PERMISSIONS_SEND = "FILE_MOVE_NO_PERMISSIONS_SEND"; -const std::string FILE_MOVE_NO_PERMISSIONS_RECEIVE = "FILE_MOVE_NO_PERMISSIONS_RECEIVE"; -const std::string FILE_MOVE_FAILED = "FILE_MOVE_FAILED"; -const std::string FILE_MOVE_SUCCEEDED = "FILE_MOVE_SUCCEEDED"; - - const std::string DEFINITION = "" " " @@ -206,15 +194,6 @@ const std::string DEFINITION = " " " " " " - " " - " " - " " - " " - " " - " " - " " - " " - " " " " " " " " @@ -226,11 +205,6 @@ const std::string DEFINITION = " " " " " " - " " - " " - " " - " " - " " " " ""; diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index e881d2f..79cd7af 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -130,15 +130,9 @@ HostIPCConnection::HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesMana setRevokeDeviceCallback(std::bind(&ZonesManager::handleRevokeDeviceCall, mZonesManagerPtr, _1, _2)); - setNotifyActiveZoneCallback(std::bind(&ZonesManager::handleNotifyActiveZoneCall, - mZonesManagerPtr, "", _1, _2)); - setSwitchToDefaultCallback(std::bind(&ZonesManager::handleSwitchToDefaultCall, mZonesManagerPtr, "", _1)); - setFileMoveCallback(std::bind(&ZonesManager::handleFileMoveCall, - mZonesManagerPtr, "", _1, _2)); - setCreateFileCallback(std::bind(&ZonesManager::handleCreateFileCall, mZonesManagerPtr, _1, _2)); } @@ -370,15 +364,6 @@ void HostIPCConnection::setRevokeDeviceCallback(const Method::type& callback) -{ - typedef IPCMethodWrapper Method; - mService->setMethodHandler( - api::ipc::METHOD_NOTIFY_ACTIVE_ZONE, - Method::getWrapper(callback)); -} - void HostIPCConnection::setSwitchToDefaultCallback(const Method::type& callback) { typedef IPCMethodWrapper Callback; @@ -387,15 +372,6 @@ void HostIPCConnection::setSwitchToDefaultCallback(const Method::type Callback::getWrapper(callback)); } -void HostIPCConnection::setFileMoveCallback(const Method::type& callback) -{ - typedef IPCMethodWrapper Method; - mService->setMethodHandler( - api::ipc::METHOD_FILE_MOVE_REQUEST, - Method::getWrapper(callback)); -} - void HostIPCConnection::setCreateFileCallback(const Method::type& callback) { @@ -405,10 +381,4 @@ void HostIPCConnection::setCreateFileCallback(const Methodsignal(api::ipc::SIGNAL_NOTIFICATION, - std::make_shared(notification)); -} - } // namespace vasum diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index dcadc4a..15620bf 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -53,7 +53,6 @@ public: void start(); void signalZoneConnectionState(const api::ConnectionState& connectionState); - void sendNotification(const api::Notification& notification); private: void setLockQueueCallback(const Method::type& callback); @@ -84,10 +83,7 @@ private: void setUnlockZoneCallback(const Method::type& callback); void setGrantDeviceCallback(const Method::type& callback); void setRevokeDeviceCallback(const Method::type& callback); - void setNotifyActiveZoneCallback(const Method::type& callback); void setSwitchToDefaultCallback(const Method::type& callback); - void setFileMoveCallback(const Method::type& callback); void setCreateFileCallback(const Method::type& callback); std::unique_ptr mService; diff --git a/server/host-ipc-definitions.hpp b/server/host-ipc-definitions.hpp index 74cf534..5fb6114 100644 --- a/server/host-ipc-definitions.hpp +++ b/server/host-ipc-definitions.hpp @@ -61,17 +61,6 @@ const ::ipc::MethodID METHOD_LOCK_QUEUE = 28; const ::ipc::MethodID METHOD_UNLOCK_QUEUE = 29; const ::ipc::MethodID METHOD_SWITCH_TO_DEFAULT = 30; -const ::ipc::MethodID METHOD_NOTIFY_ACTIVE_ZONE = 100; -const ::ipc::MethodID METHOD_FILE_MOVE_REQUEST = 101; -const ::ipc::MethodID SIGNAL_NOTIFICATION = 102; - -const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND"; -const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION"; -const std::string FILE_MOVE_NO_PERMISSIONS_SEND = "FILE_MOVE_NO_PERMISSIONS_SEND"; -const std::string FILE_MOVE_NO_PERMISSIONS_RECEIVE = "FILE_MOVE_NO_PERMISSIONS_RECEIVE"; -const std::string FILE_MOVE_FAILED = "FILE_MOVE_FAILED"; -const std::string FILE_MOVE_SUCCEEDED = "FILE_MOVE_SUCCEEDED"; - } // namespace ipc } // namespace api } // namespace vasum diff --git a/server/zone-config.hpp b/server/zone-config.hpp index 01fc728..0330e57 100644 --- a/server/zone-config.hpp +++ b/server/zone-config.hpp @@ -70,18 +70,6 @@ struct ZoneConfig { std::int64_t cpuQuotaBackground; /** - * When you move a file out of the zone (by move request) - * its path must match at least one of the regexps in this vector. - */ - std::vector permittedToSend; - - /** - * When you move a file to the zone (by move request) - * its path must match at least one of the regexps in this vector. - */ - std::vector permittedToRecv; - - /** * Valid hard link prefixes. */ std::vector validLinkPrefixes; @@ -102,8 +90,6 @@ struct ZoneConfig { switchToDefaultAfterTimeout, // TODO move to dynamic and add an API to change cpuQuotaForeground, cpuQuotaBackground, - permittedToSend, // TODO move to dynamic and add an API to change - permittedToRecv, // TODO move to dynamic and add an API to change validLinkPrefixes, shutdownTimeout ) diff --git a/server/zone.cpp b/server/zone.cpp index 590badd..5170f5a 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -78,13 +78,6 @@ Zone::Zone(const std::string& zoneId, config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mConfig, dbPrefix); config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mDynamicConfig, dbPrefix); - for (std::string r: mConfig.permittedToSend) { - mPermittedToSend.push_back(boost::regex(r)); - } - for (std::string r: mConfig.permittedToRecv) { - mPermittedToRecv.push_back(boost::regex(r)); - } - if (!mDynamicConfig.runMountPoint.empty()) { mRunMountPoint = fs::absolute(mDynamicConfig.runMountPoint, baseRunMountPointPath).string(); } @@ -141,16 +134,6 @@ Zone::~Zone() LOGD(mId << ": Zone object destroyed"); } -const std::vector& Zone::getPermittedToSend() const -{ - return mPermittedToSend; -} - -const std::vector& Zone::getPermittedToRecv() const -{ - return mPermittedToRecv; -} - const std::string& Zone::getId() const { Lock lock(mReconnectMutex); diff --git a/server/zone.hpp b/server/zone.hpp index dbc384d..0d3a920 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -74,18 +74,6 @@ public: typedef std::function StartAsyncResultCallback; /** - * Returns a vector of regexps defining files permitted to be - * send to other zones using file move functionality - */ - const std::vector& getPermittedToSend() const; - - /** - * Returns a vector of regexps defining files permitted to be - * send to other zones using file move functionality - */ - const std::vector& getPermittedToRecv() const; - - /** * Get the zone id */ const std::string& getId() const; @@ -286,8 +274,6 @@ public: private: ZoneConfig mConfig; ZoneDynamicConfig mDynamicConfig; - std::vector mPermittedToSend; - std::vector mPermittedToRecv; std::unique_ptr mProvision; mutable std::recursive_mutex mReconnectMutex; std::string mRunMountPoint; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 98b5a1e..8ed51e1 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -52,18 +52,6 @@ namespace vasum { namespace { -#ifdef ZONE_CONNECTION -bool regexMatchVector(const std::string& str, const std::vector& v) -{ - for (const boost::regex& toMatch : v) { - if (boost::regex_match(str, toMatch)) { - return true; - } - } - - return false; -} -#endif const std::string HOST_ID = "host"; const std::string ENABLED_FILE_NAME = "enabled"; @@ -522,144 +510,6 @@ void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/, tryAddTask(handler, result, true); } -#ifdef ZONE_CONNECTION -void ZonesManager::handleNotifyActiveZoneCall(const std::string& caller, - const api::NotifActiveZoneIn& notif, - api::MethodResultBuilder::Pointer result) -{ - auto handler = [&, this] { - const std::string& application = notif.first; - const std::string& message = notif.second; - LOGI("handleNotifyActiveZoneCall(" << caller << ", " << application << ", " << message - << ") called"); - - Lock lock(mMutex); - - try { - auto iter = getRunningForegroundZoneIterator(); - if (iter != mZones.end() && caller != get(iter).getId()) { - //XXX:get(iter).sendNotification(caller, application, message); - } - result->setVoid(); - } catch (const std::runtime_error&) { - LOGE("Notification from " << caller << " hasn't been sent"); - result->setError(api::ERROR_INTERNAL, "Notification hasn't been sent"); - } - }; - - tryAddTask(handler, result, true); -} - -void ZonesManager::handleFileMoveCall(const std::string& srcZoneId, - const api::FileMoveRequestIn& request, - api::MethodResultBuilder::Pointer result) -{ - // TODO: this implementation is only a placeholder. - // There are too many unanswered questions and security concerns: - // 1. What about mount namespace, host might not see the source/destination - // file. The file might be a different file from a host perspective. - // 2. Copy vs move (speed and security concerns over already opened FDs) - // 3. Access to source and destination files - DAC, uid/gig - // 4. Access to source and destintation files - MAC, smack - // 5. Destination file uid/gid assignment - // 6. Destination file smack label assignment - // 7. Verifiability of the source path - - // NOTE: other possible implementations include: - // 1. Sending file descriptors opened directly in each zone through DBUS - // using something like g_dbus_message_set_unix_fd_list() - // 2. VSM forking and calling setns(MNT) in each zone and opening files - // by itself, then passing FDs to the main process - // Now when the main process has obtained FDs (by either of those methods) - // it can do the copying by itself. - - auto handler = [&, this] { - const std::string& dstZoneId = request.first; - const std::string& path = request.second; - LOGI("File move requested\n" - << "src: " << srcZoneId << "\n" - << "dst: " << dstZoneId << "\n" - << "path: " << path); - - Lock lock(mMutex); - - auto srcIter = findZone(srcZoneId); - if (srcIter == mZones.end()) { - LOGE("Source zone '" << srcZoneId << "' not found"); - return; - } - Zone& srcZone = get(srcIter); - - auto status = std::make_shared(); - - auto dstIter = findZone(dstZoneId); - if (dstIter == mZones.end()) { - LOGE("Destination zone '" << dstZoneId << "' not found"); - status->value = api::FILE_MOVE_DESTINATION_NOT_FOUND; - result->set(status); - return; - } - Zone& dstContanier = get(dstIter); - - if (srcZoneId == dstZoneId) { - LOGE("Cannot send a file to yourself"); - status->value = api::FILE_MOVE_WRONG_DESTINATION; - result->set(status); - return; - } - - if (!regexMatchVector(path, srcZone.getPermittedToSend())) { - LOGE("Source zone has no permissions to send the file: " << path); - status->value = api::FILE_MOVE_NO_PERMISSIONS_SEND; - result->set(status); - return; - } - - if (!regexMatchVector(path, dstContanier.getPermittedToRecv())) { - LOGE("Destination zone has no permissions to receive the file: " << path); - status->value = api::FILE_MOVE_NO_PERMISSIONS_RECEIVE; - result->set(status); - return; - } - - namespace fs = boost::filesystem; - std::string srcPath = fs::absolute(srcZoneId, mConfig.zonesPath).string() + path; - std::string dstPath = fs::absolute(dstZoneId, mConfig.zonesPath).string() + path; - - if (!utils::moveFile(srcPath, dstPath)) { - LOGE("Failed to move the file: " << path); - status->value = api::FILE_MOVE_FAILED; - result->set(status); - } else { - status->value = api::FILE_MOVE_SUCCEEDED; - result->set(status); - try { - //XXX: dstContanier.sendNotification(srcZoneId, path, api::FILE_MOVE_SUCCEEDED); - } catch (ServerException&) { - LOGE("Notification to '" << dstZoneId << "' has not been sent"); - } - } - }; - - tryAddTask(handler, result, true); -} -#else -void ZonesManager::handleNotifyActiveZoneCall(const std::string& /* caller */, - const api::NotifActiveZoneIn& /*notif*/, - api::MethodResultBuilder::Pointer result) -{ - result->setError(api::ERROR_INTERNAL, "Not implemented"); -} - -void ZonesManager::handleFileMoveCall(const std::string& /*srcZoneId*/, - const api::FileMoveRequestIn& /*request*/, - api::MethodResultBuilder::Pointer result) -{ - result->setError(api::ERROR_INTERNAL, "Not implemented"); -} - -#endif /* ZONE_CONNECTION */ - void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request, api::MethodResultBuilder::Pointer result) { diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 75f83a7..4d18bf7 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -176,16 +176,8 @@ public: api::MethodResultBuilder::Pointer result); void handleCreateFileCall(const api::CreateFileIn& request, api::MethodResultBuilder::Pointer result); - - // Zone's handlers--------------------------------------------------------- - void handleNotifyActiveZoneCall(const std::string& caller, - const api::NotifActiveZoneIn& notif, - api::MethodResultBuilder::Pointer result); void handleSwitchToDefaultCall(const std::string& caller, api::MethodResultBuilder::Pointer result); - void handleFileMoveCall(const std::string& srcZoneId, - const api::FileMoveRequestIn& request, - api::MethodResultBuilder::Pointer result); private: typedef std::recursive_mutex Mutex; diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 2fea841..b352b9c 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -343,78 +343,6 @@ BOOST_AUTO_TEST_CASE(LockUnlockZone) vsm_client_free(client); } -#ifdef ZONE_CONNECTION -BOOST_AUTO_TEST_CASE(FileMoveRequest) -{ - const std::string path = "/tmp/fake_path"; - const std::string secondZone = "fake_zone"; - - VsmClient client = vsm_client_create(); - VsmStatus status = vsm_connect(client); - 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); - BOOST_REQUIRE_EQUAL(api::FILE_MOVE_DESTINATION_NOT_FOUND, - vsm_get_status_message(client)); - vsm_client_free(client); -} - -BOOST_AUTO_TEST_CASE(Notification) -{ - const std::string MSG_CONTENT = "msg"; - const std::string MSG_APP = "app"; - - struct CallbackData { - Latch signalReceivedLatch; - std::vector< std::tuple > receivedSignalMsg; - }; - - auto callback = [](const char* zone, - const char* application, - const char* message, - void* data) { - CallbackData& callbackData = *reinterpret_cast(data); - callbackData.receivedSignalMsg.push_back(std::make_tuple(zone, application, message)); - callbackData.signalReceivedLatch.set(); - }; - - CallbackData callbackData; - std::map clients; - for (const auto& it : EXPECTED_ZONES) { - VsmClient client = vsm_client_create(); - VsmStatus status = vsm_connect_custom(client, it.c_str()); - BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); - clients[it.first] = client; - } - for (auto& client : clients) { - VsmStatus status = vsm_add_notification_callback(client.second, - callback, - &callbackData, - NULL); - BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); - } - for (auto& client : clients) { - VsmStatus status = vsm_notify_active_zone(client.second, - MSG_APP.c_str(), - MSG_CONTENT.c_str()); - BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status); - } - - BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1u, EVENT_TIMEOUT)); - BOOST_CHECK(callbackData.signalReceivedLatch.empty()); - - for (const auto& msg : callbackData.receivedSignalMsg) { - BOOST_CHECK(clients.count(std::get<0>(msg)) > 0); - BOOST_CHECK_EQUAL(std::get<1>(msg), MSG_APP); - BOOST_CHECK_EQUAL(std::get<2>(msg), MSG_CONTENT); - } - - for (auto& client : clients) { - vsm_client_free(client.second); - } -} -#endif - BOOST_AUTO_TEST_CASE(GetZoneIdByPidTestSingle) { VsmClient client = vsm_client_create(); diff --git a/tests/unit_tests/configs/templates/buggy-init.conf b/tests/unit_tests/configs/templates/buggy-init.conf index cff3576..a13246c 100644 --- a/tests/unit_tests/configs/templates/buggy-init.conf +++ b/tests/unit_tests/configs/templates/buggy-init.conf @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/configs/templates/buggy-template.conf b/tests/unit_tests/configs/templates/buggy-template.conf index d89364d..23b77a6 100644 --- a/tests/unit_tests/configs/templates/buggy-template.conf +++ b/tests/unit_tests/configs/templates/buggy-template.conf @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/configs/templates/console-dbus.conf.in b/tests/unit_tests/configs/templates/console-dbus.conf.in index ef8a63e..4daff1d 100644 --- a/tests/unit_tests/configs/templates/console-dbus.conf.in +++ b/tests/unit_tests/configs/templates/console-dbus.conf.in @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "/tmp/ut-run/~NAME~", "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/configs/templates/console-ipc.conf.in b/tests/unit_tests/configs/templates/console-ipc.conf.in index a4d43b0..cefd3e7 100644 --- a/tests/unit_tests/configs/templates/console-ipc.conf.in +++ b/tests/unit_tests/configs/templates/console-ipc.conf.in @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "/tmp/ut-run/~NAME~", "provisions" : [], - "permittedToSend" : [ "/tmp/.*" ], - "permittedToRecv" : [ "/tmp/.*" ], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/configs/templates/default.conf b/tests/unit_tests/configs/templates/default.conf index 6b0eaa7..cd9ae0b 100644 --- a/tests/unit_tests/configs/templates/default.conf +++ b/tests/unit_tests/configs/templates/default.conf @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], "validLinkPrefixes" : [ "/tmp" ] } diff --git a/tests/unit_tests/configs/templates/missing.conf b/tests/unit_tests/configs/templates/missing.conf index 9a37d54..1d19915 100644 --- a/tests/unit_tests/configs/templates/missing.conf +++ b/tests/unit_tests/configs/templates/missing.conf @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/configs/templates/test-no-shutdown.conf b/tests/unit_tests/configs/templates/test-no-shutdown.conf index e0aec5b..f8ab796 100644 --- a/tests/unit_tests/configs/templates/test-no-shutdown.conf +++ b/tests/unit_tests/configs/templates/test-no-shutdown.conf @@ -12,7 +12,5 @@ "shutdownTimeout" : 10, "runMountPoint" : "", "provisions" : [], - "permittedToSend" : [], - "permittedToRecv" : [], "validLinkPrefixes" : [] } diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index cd402b8..a6502fd 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -110,7 +110,6 @@ public: MethodResultBuilder::Pointer result )> TestApiMethodCallback; typedef std::function VoidResultCallback; - typedef std::function NotificationCallback; typedef std::map Connections; HostDbusAccessory() @@ -167,29 +166,6 @@ public: mClient->signalSubscribe(callback, isHost() ? api::dbus::BUS_NAME : api::dbus::BUS_NAME); } - void subscribeNotification(const NotificationCallback& callback) - { - auto handler = [callback](const std::string& /*senderBusName*/, - const std::string& objectPath, - const std::string& interface, - const std::string& signalName, - GVariant* parameters) - { - if (objectPath == api::dbus::OBJECT_PATH && - interface == api::dbus::INTERFACE && - signalName == api::dbus::SIGNAL_NOTIFICATION && - g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) { - - const gchar* zone = NULL; - const gchar* application = NULL; - const gchar* message = NULL; - g_variant_get(parameters, "(&s&s&s)", &zone, &application, &message); - callback({zone, application, message}); - } - }; - mClient->signalSubscribe(handler, api::dbus::BUS_NAME); - } - void callSwitchToDefault() { mClient->callMethod(api::dbus::BUS_NAME, @@ -200,32 +176,6 @@ public: "()"); } - void callMethodNotify() - { - GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSAGE.c_str()); - mClient->callMethod(api::dbus::BUS_NAME, - api::dbus::OBJECT_PATH, - api::dbus::INTERFACE, - api::dbus::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::dbus::BUS_NAME, - api::dbus::OBJECT_PATH, - api::dbus::INTERFACE, - api::dbus::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, @@ -493,7 +443,6 @@ private: class HostIPCAccessory { public: typedef std::function VoidResultCallback; - typedef std::function NotificationCallback; HostIPCAccessory() : mClient(mDispatcher.getPoll(), HOST_IPC_SOCKET) @@ -588,15 +537,6 @@ public: EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone } - void subscribeNotification(const NotificationCallback& callback) - { - auto callbackWrapper = [callback] (const ipc::PeerID, std::shared_ptr& data) { - callback(*data); - }; - mClient.setSignalHandler(api::ipc::SIGNAL_NOTIFICATION, - callbackWrapper); - } - void callSwitchToDefault() { mClient.callSync(api::ipc::METHOD_SWITCH_TO_DEFAULT, @@ -604,23 +544,6 @@ public: EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone } - void callMethodNotify() - { - mClient.callSync( - api::ipc::METHOD_NOTIFY_ACTIVE_ZONE, - std::make_shared(api::NotifActiveZoneIn{TEST_APP_NAME, TEST_MESSAGE}), - EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone - } - - std::string callMethodMove(const std::string& dest, const std::string& path) - { - auto result = mClient.callSync( - api::ipc::METHOD_FILE_MOVE_REQUEST, - std::make_shared(api::FileMoveRequestIn{dest, path}), - EVENT_TIMEOUT*10); - return result->value; - } - int callMethodCreateFile(const std::string& id, const std::string& path, const std::int32_t& flags, @@ -751,151 +674,6 @@ BOOST_AUTO_TEST_CASE(Focus) BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone3"); } -#ifdef ZONE_CONNECTION -BOOST_AUTO_TEST_CASE(NotifyActiveZone) -{ - ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); - cm.createZone("zone1", SIMPLE_TEMPLATE); - cm.createZone("zone2", SIMPLE_TEMPLATE); - cm.createZone("zone3", SIMPLE_TEMPLATE); - cm.restoreAll(); - - Latch signalReceivedLatch; - std::map> signalReceivedSourcesMap; - - std::map> connections; - for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - connections[i] = std::unique_ptr(new ZoneAccessory(i)); - } - - auto handler = [](Latch& latch, - std::vector& receivedSignalSources, - const api::Notification& notify) - { - receivedSignalSources.push_back(notify.zone); - if (notify.application == TEST_APP_NAME && notify.message == TEST_MESSAGE) { - latch.set(); - } - }; - - using namespace std::placeholders; - for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) { - connections[i]->subscribeNotification(std::bind(handler, - std::ref(signalReceivedLatch), - std::ref(signalReceivedSourcesMap[i]), - _1)); - } - for (auto& connection : connections) { - connection.second->callMethodNotify(); - } - - 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 - for (const auto& source : signalReceivedSourcesMap[1]) { - BOOST_CHECK_EQUAL(std::count(signalReceivedSourcesMap[1].begin(), - signalReceivedSourcesMap[1].end(), - source), 1); - } - //check if all signals was received by active zone - BOOST_CHECK_EQUAL(signalReceivedSourcesMap[1].size(), connections.size() - 1); - //check if no signals was received by inactive zone - for (size_t i = 2; i <= connections.size(); ++i) { - BOOST_CHECK(signalReceivedSourcesMap[i].empty()); - } - - connections.clear(); -} - -BOOST_AUTO_TEST_CASE(MoveFile) -{ - ZonesManager cm(dispatcher.getPoll(), TEST_CONFIG_PATH); - cm.createZone("zone1", SIMPLE_TEMPLATE); - cm.createZone("zone2", SIMPLE_TEMPLATE); - cm.createZone("zone3", SIMPLE_TEMPLATE); - cm.restoreAll(); - - Latch notificationLatch; - std::string notificationSource; - std::string notificationPath; - std::string notificationRetcode; - - std::map> connections; - for (int i = 1; i <= 2; ++i) { - connections[i] = std::unique_ptr(new ZoneAccessory(i)); - } - - auto handler = [&](const api::Notification& notify) - { - notificationSource = notify.zone; - notificationPath = notify.application; - notificationRetcode = notify.message; - notificationLatch.set(); - }; - - // subscribe the second (destination) zone for notifications - connections.at(2)->subscribeNotification(handler); - - const std::string TMP = "/tmp/ut-zones"; - const std::string NO_PATH = "path_doesnt_matter_here"; - const std::string BUGGY_PATH = TMP + "/this_file_does_not_exist"; - const std::string BUGGY_ZONE = "this-zone-does-not-exist"; - const std::string ZONE1 = "zone1"; - const std::string ZONE2 = "zone2"; - const std::string ZONE1PATH = TMP + "/" + ZONE1 + TMP; - const std::string ZONE2PATH = TMP + "/" + ZONE2 + TMP; - - // sending to a non existing zone - BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(BUGGY_ZONE, NO_PATH), - api::FILE_MOVE_DESTINATION_NOT_FOUND); - BOOST_CHECK(notificationLatch.empty()); - - // sending to self - BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE1, NO_PATH), - api::FILE_MOVE_WRONG_DESTINATION); - BOOST_CHECK(notificationLatch.empty()); - - // no permission to send - BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, "/etc/secret1"), - api::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(connections.at(1)->callMethodMove(ZONE2, "/etc/secret2"), - // api::FILE_MOVE_NO_PERMISSIONS_RECEIVE); - //BOOST_CHECK(notificationLatch.empty()); - - // non existing file - BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, BUGGY_PATH), - api::FILE_MOVE_FAILED); - BOOST_CHECK(notificationLatch.empty()); - - // a working scenario - namespace fs = boost::filesystem; - boost::system::error_code ec; - fs::remove_all(ZONE1PATH, ec); - fs::remove_all(ZONE2PATH, ec); - BOOST_REQUIRE(fs::create_directories(ZONE1PATH, ec)); - BOOST_REQUIRE(fs::create_directories(ZONE2PATH, ec)); - BOOST_REQUIRE(utils::saveFileContent(ZONE1PATH + "/file", FILE_CONTENT)); - - BOOST_CHECK_EQUAL(connections.at(1)->callMethodMove(ZONE2, TMP + "/file"), - api::FILE_MOVE_SUCCEEDED); - BOOST_REQUIRE(notificationLatch.wait(EVENT_TIMEOUT)); - BOOST_REQUIRE(notificationLatch.empty()); - BOOST_CHECK_EQUAL(notificationSource, ZONE1); - BOOST_CHECK_EQUAL(notificationPath, TMP + "/file"); - BOOST_CHECK_EQUAL(notificationRetcode, api::FILE_MOVE_SUCCEEDED); - BOOST_CHECK(!fs::exists(ZONE1PATH + "/file")); - BOOST_CHECK_EQUAL(utils::readFileContent(ZONE2PATH + "/file"), FILE_CONTENT); - - fs::remove_all(ZONE1PATH, ec); - fs::remove_all(ZONE2PATH, ec); -} -#endif - MULTI_FIXTURE_TEST_CASE(SwitchToDefault, F, ACCESSORS) { ZonesManager cm(F::dispatcher.getPoll(), TEST_CONFIG_PATH); -- 2.7.4 From 9c8372a3b072506d5c4230058169cdb6ad3729e0 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Tue, 7 Jul 2015 13:13:45 +0200 Subject: [PATCH 16/16] Handling signals with signalfd [Feature] Synchronous signal handling [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I5a31fcb9929a3d8d36c1ea275c089412687478d5 --- common/utils/signal.cpp | 79 ++++++++++++++++++++++++++----- common/utils/signal.hpp | 8 +++- common/utils/signalfd.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++ common/utils/signalfd.hpp | 82 +++++++++++++++++++++++++++++++++ libs/ipc/epoll/event-poll.hpp | 2 +- server/main.cpp | 5 ++ server/server.cpp | 57 +++++++++-------------- server/server.hpp | 6 ++- zone-daemon/CMakeLists.txt | 2 +- 9 files changed, 296 insertions(+), 50 deletions(-) create mode 100644 common/utils/signalfd.cpp create mode 100644 common/utils/signalfd.hpp diff --git a/common/utils/signal.cpp b/common/utils/signal.cpp index 2daa766..17ec003 100644 --- a/common/utils/signal.cpp +++ b/common/utils/signal.cpp @@ -33,26 +33,83 @@ namespace utils { -void signalBlock(const int signalToBlock) +namespace { + +void setSignalMask(int how, const ::sigset_t& set) { + int ret = ::pthread_sigmask(how, &set, nullptr /*&oldSet*/); + if(ret != 0) { + const std::string msg = getSystemErrorMessage(ret); + LOGE("Error in pthread_sigmask: " << msg); + throw UtilsException("Error in pthread_sigmask: " + msg); + } +} + +void changeSignal(int how, const int sigNum) { ::sigset_t set; - if (-1 == ::sigemptyset(&set)) { + if(-1 == ::sigemptyset(&set)) { const std::string msg = getSystemErrorMessage(); - LOGE("Error in sigemptyset: " << msg); - throw UtilsException("Error in sigemptyset: " + msg); + LOGE("Error in sigfillset: " << msg); + throw UtilsException("Error in sigfillset: " + msg); } - if (-1 ==::sigaddset(&set, signalToBlock)) { + if(-1 ==::sigaddset(&set, sigNum)) { const std::string msg = getSystemErrorMessage(); - LOGE("Error in sigaddset: " << msg); - throw UtilsException("Error in sigaddset: " + msg); + LOGE("Error in sigdelset: " << msg); + throw UtilsException("Error in sigdelset: " + msg); } - int ret = ::pthread_sigmask(SIG_BLOCK, &set, nullptr /*&oldSet*/); - if (ret != 0) { - LOGE("Error in pthread_sigmask: " << std::to_string(ret)); - throw UtilsException("Error in pthread_sigmask: " + std::to_string(ret)); + setSignalMask(how, set); +} + +}// namespace + +::sigset_t getSignalMask() +{ + ::sigset_t set; + int ret = ::pthread_sigmask(0 /*ignored*/, nullptr /*get the oldset*/, &set); + if(ret != 0) { + const std::string msg = getSystemErrorMessage(ret); + LOGE("Error in pthread_sigmask: " << msg); + throw UtilsException("Error in pthread_sigmask: " + msg); + } + return set; +} + +bool isSignalBlocked(const int sigNum) +{ + ::sigset_t set = getSignalMask(); + + int ret = ::sigismember(&set, sigNum); + if(-1 == ret) { + const std::string msg = getSystemErrorMessage(); + LOGE("Error in sigismember: " << msg); + throw UtilsException("Error in sigismember: " + msg); } + + return ret == 1; +} + +void signalBlock(const int sigNum) +{ + changeSignal(SIG_BLOCK, sigNum); +} + +void signalBlockAll() +{ + ::sigset_t set; + if(-1 == ::sigfillset(&set)) { + const std::string msg = getSystemErrorMessage(); + LOGE("Error in sigfillset: " << msg); + throw UtilsException("Error in sigfillset: " + msg); + } + + setSignalMask(SIG_BLOCK, set); +} + +void signalUnblock(const int sigNum) +{ + changeSignal(SIG_UNBLOCK, sigNum); } } // namespace utils diff --git a/common/utils/signal.hpp b/common/utils/signal.hpp index c466688..4cd5a5a 100644 --- a/common/utils/signal.hpp +++ b/common/utils/signal.hpp @@ -25,9 +25,15 @@ #ifndef COMMON_UTILS_SIGNAL_HPP #define COMMON_UTILS_SIGNAL_HPP +#include + namespace utils { -void signalBlock(const int signalsToBlock); +::sigset_t getSignalMask(); +bool isSignalBlocked(const int sigNum); +void signalBlockAll(); +void signalBlock(const int sigNum); +void signalUnblock(const int sigNum); } // namespace utils diff --git a/common/utils/signalfd.cpp b/common/utils/signalfd.cpp new file mode 100644 index 0000000..0b3250f --- /dev/null +++ b/common/utils/signalfd.cpp @@ -0,0 +1,105 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Eventfd wrapper + */ + +#include "utils/signalfd.hpp" +#include "utils/signal.hpp" +#include "utils/fd-utils.hpp" +#include "utils/exception.hpp" +#include "logger/logger.hpp" + +#include + +namespace utils { + +SignalFD::SignalFD(ipc::epoll::EventPoll& eventPoll) + :mEventPoll(eventPoll) +{ + ::sigset_t set = getSignalMask(); + + mFD = ::signalfd(-1, &set, SFD_CLOEXEC); + if (mFD == -1) { + const std::string msg = getSystemErrorMessage(); + LOGE("Error in signalfd: " << msg); + throw UtilsException("Error in signalfd: " + msg); + } + + mEventPoll.addFD(mFD, EPOLLIN, std::bind(&SignalFD::handleInternal, this)); +} + +SignalFD::~SignalFD() +{ + mEventPoll.removeFD(mFD); + utils::close(mFD); +} + +int SignalFD::getFD() const +{ + return mFD; +} + +void SignalFD::setHandler(const int sigNum, const Callback&& callback) +{ + Lock lock(mMutex); + + bool isBlocked = isSignalBlocked(sigNum); + + ::sigset_t set = getSignalMask(); + if(!isBlocked) { + signalBlock(sigNum); + } + + int error = ::signalfd(mFD, &set, SFD_CLOEXEC); + if (error != mFD) { + const std::string msg = getSystemErrorMessage(); + LOGE("Error in signalfd: " << msg); + if(!isBlocked) { + signalUnblock(sigNum); + } + throw UtilsException("Error in signalfd: " + msg); + } + + mCallbacks.insert({sigNum, callback}); +} + +void SignalFD::handleInternal() +{ + signalfd_siginfo sigInfo; + utils::read(mFD, &sigInfo, sizeof(sigInfo)); + + LOGD("Got signal: " << sigInfo.ssi_signo); + + { + Lock lock(mMutex); + auto it = mCallbacks.find(sigInfo.ssi_signo); + if (it == mCallbacks.end()) { + // Meantime the callback was deleted + LOGE("No callback for signal: " << sigInfo.ssi_signo); + return; + } + + it->second(sigInfo.ssi_signo); + } +} + +} // namespace utils diff --git a/common/utils/signalfd.hpp b/common/utils/signalfd.hpp new file mode 100644 index 0000000..5410a34 --- /dev/null +++ b/common/utils/signalfd.hpp @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Eventfd wrapper + */ + +#ifndef COMMON_UTILS_SIGNALFD_HPP +#define COMMON_UTILS_SIGNALFD_HPP + +#include "ipc/epoll/event-poll.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace utils { + +/** + * SignalFD takes control over handling signals + * sent to the thread. + * + * It should be the only place where signal masks are modified. + */ +class SignalFD { +public: + typedef std::function Callback; + + SignalFD(ipc::epoll::EventPoll& eventPoll); + ~SignalFD(); + + SignalFD(const SignalFD& signalfd) = delete; + SignalFD& operator=(const SignalFD&) = delete; + + /** + * Add a callback for a specified signal + * + * @param sigNum number of the signal + * @param callback handler callback + */ + void setHandler(const int sigNum, const Callback&& callback); + + /** + * @return signal file descriptor + */ + int getFD() const; + +private: + typedef std::unique_lock Lock; + + int mFD; + std::mutex mMutex; + ipc::epoll::EventPoll& mEventPoll; + std::unordered_map mCallbacks; + + void handleInternal(); +}; + +} // namespace utils + +#endif // COMMON_UTILS_SIGNALFD_HPP diff --git a/libs/ipc/epoll/event-poll.hpp b/libs/ipc/epoll/event-poll.hpp index 5e84ee3..ba82497 100644 --- a/libs/ipc/epoll/event-poll.hpp +++ b/libs/ipc/epoll/event-poll.hpp @@ -49,7 +49,7 @@ public: void removeFD(const int fd); /** - * Dispatch at most one signalled FD + * Dispatch at most one signaled FD * @param timeoutMs how long should wait in case of no pending events * (0 - return immediately, -1 - wait forever) * @return false on timeout diff --git a/server/main.cpp b/server/main.cpp index 55a795e..513a4f3 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -37,6 +37,7 @@ #include "logger/backend-stderr.hpp" #include "logger/backend-journal.hpp" #include "utils/typeinfo.hpp" +#include "utils/signal.hpp" #include #include @@ -121,6 +122,10 @@ int main(int argc, char* argv[]) } try { + // Block all signals + // Server will unblock handled signals + utils::signalBlockAll(); + Server server(CONFIG_PATH); server.run(runAsRoot); server.reloadIfRequired(argv); diff --git a/server/server.cpp b/server/server.cpp index 5abd430..c8413c7 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -78,68 +77,55 @@ using namespace utils; namespace vasum { - Server::Server(const std::string& configPath) - : mConfigPath(configPath) + : mIsUpdate(false), + mConfigPath(configPath), + mSignalFD(mDispatcher.getPoll()) { -} - - -namespace { - -std::atomic_bool gUpdateTriggered(false); -utils::Latch gSignalLatch; + mSignalFD.setHandler(SIGINT, [this](int) { + mStopLatch.set(); + }); -void signalHandler(const int sig) -{ - LOGI("Got signal " << sig); + mSignalFD.setHandler(SIGTERM, [this] (int) { + mStopLatch.set(); + }); - if (sig == SIGUSR1) { + mSignalFD.setHandler(SIGUSR1, [this] (int) { LOGD("Received SIGUSR1 - triggering update."); - gUpdateTriggered = true; - } - - gSignalLatch.set(); + mIsUpdate = true; + mStopLatch.set(); + }); } -} // namespace - void Server::run(bool asRoot) { if (!prepareEnvironment(mConfigPath, asRoot)) { throw ServerException("Environment setup failed"); } - signal(SIGINT, signalHandler); - signal(SIGTERM, signalHandler); - signal(SIGUSR1, signalHandler); - utils::signalBlock(SIGPIPE); - LOGI("Starting daemon..."); { utils::ScopedGlibLoop loop; ZonesManager manager(mDispatcher.getPoll(), mConfigPath); // Do not restore zones state at Vasum start - // manager.restoreAll(); LOGI("Daemon started"); - gSignalLatch.wait(); + mStopLatch.wait(); // Detach zones if we triggered an update - if (gUpdateTriggered) { + if (mIsUpdate) { manager.setZonesDetachOnExit(); } LOGI("Stopping daemon..."); - // manager.shutdownAll() will be called in destructor } LOGI("Daemon stopped"); } void Server::reloadIfRequired(char* argv[]) { - if (gUpdateTriggered) { + if (mIsUpdate) { execve(argv[0], argv, environ); LOGE("Failed to reload " << argv[0] << ": " << getSystemErrorMessage()); } @@ -148,7 +134,7 @@ void Server::reloadIfRequired(char* argv[]) void Server::terminate() { LOGI("Terminating server"); - gSignalLatch.set(); + mStopLatch.set(); } bool Server::checkEnvironment() @@ -267,10 +253,11 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) // directory or symlink // CAP_SETUID is needed to launch specific funtions as root (see environment.cpp) return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, - CAP_MAC_OVERRIDE, - CAP_SYS_TTY_CONFIG, - CAP_CHOWN, - CAP_SETUID})); + CAP_MAC_OVERRIDE, + CAP_SYS_TTY_CONFIG, + CAP_CHOWN, + CAP_SETUID + })); } diff --git a/server/server.hpp b/server/server.hpp index bf2519b..0d10396 100644 --- a/server/server.hpp +++ b/server/server.hpp @@ -27,8 +27,10 @@ #define SERVER_SERVER_HPP #include "utils/latch.hpp" +#include "utils/signalfd.hpp" #include "ipc/epoll/thread-dispatcher.hpp" +#include #include @@ -61,9 +63,11 @@ public: static bool checkEnvironment(); private: + std::atomic_bool mIsUpdate; std::string mConfigPath; + utils::Latch mStopLatch; ipc::epoll::ThreadDispatcher mDispatcher; - + utils::SignalFD mSignalFD; /** * Set needed caps, groups and drop root privileges. */ diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt index 4944dfb..7171eee 100644 --- a/zone-daemon/CMakeLists.txt +++ b/zone-daemon/CMakeLists.txt @@ -43,7 +43,7 @@ SET_TARGET_PROPERTIES(${ZONE_DAEMON_CODENAME} PROPERTIES ) TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} ${ZONE_DAEMON_DEPS_LIBRARIES} - ${Boost_LIBRARIES} Logger SimpleDbus) + ${Boost_LIBRARIES} Logger SimpleDbus Ipc) ## Install ##################################################################### -- 2.7.4