From aa1f5f7317a73b7063b7ca4cc4872cc6271c79d2 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Tue, 19 May 2015 18:38:11 +0200 Subject: [PATCH 01/16] Fix GetZoneIdByPidTestMultiple, GrantRevoke [Feature] GetZoneIdByPidTestMultiple, GrantRevoke some times fails [Cause] Timeout was too small [Solution] Increase timeout [Verification] Build, install, run tests Change-Id: Id191c1a6443e19f729dfc90c9a3c8c34dc4166e3 --- common/utils/fd-utils.hpp | 4 ++-- libs/config/fdstore.hpp | 4 ++-- libs/ipc/client.hpp | 2 +- libs/ipc/internals/processor.hpp | 2 +- libs/ipc/service.hpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/utils/fd-utils.hpp b/common/utils/fd-utils.hpp index 151eb1c..209de2c 100644 --- a/common/utils/fd-utils.hpp +++ b/common/utils/fd-utils.hpp @@ -42,7 +42,7 @@ void close(int fd); * @param size size of data to write * @param timeoutMS timeout in milliseconds */ -void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS = 500); +void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS = 5000); /** * Read from a file descriptor, throw on error. @@ -52,7 +52,7 @@ void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS = 500 * @param size size of the data to read * @param timeoutMS timeout in milliseconds */ -void read(int fd, void* bufferPtr, const size_t size, int timeoutMS = 500); +void read(int fd, void* bufferPtr, const size_t size, int timeoutMS = 5000); /** * @return the max number of file descriptors for this process. diff --git a/libs/config/fdstore.hpp b/libs/config/fdstore.hpp index d34ea14..d76fc5f 100644 --- a/libs/config/fdstore.hpp +++ b/libs/config/fdstore.hpp @@ -50,7 +50,7 @@ public: * @param size size of the buffer * @param timeoutMS timeout in milliseconds */ - void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500); + void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 5000); /** * Reads a value of the given type. @@ -59,7 +59,7 @@ public: * @param size size of the buffer * @param timeoutMS timeout in milliseconds */ - void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500); + void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 5000); private: int mFD; diff --git a/libs/ipc/client.hpp b/libs/ipc/client.hpp index c76a817..fe3345a 100644 --- a/libs/ipc/client.hpp +++ b/libs/ipc/client.hpp @@ -125,7 +125,7 @@ public: template std::shared_ptr callSync(const MethodID methodID, const std::shared_ptr& data, - unsigned int timeoutMS = 500); + unsigned int timeoutMS = 5000); /** * Asynchronous method call. The return callback will be called on diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index b1b0a5f..121978c 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -262,7 +262,7 @@ public: std::shared_ptr callSync(const MethodID methodID, const PeerID peerID, const std::shared_ptr& data, - unsigned int timeoutMS = 500); + unsigned int timeoutMS = 5000); /** * Asynchronous method call diff --git a/libs/ipc/service.hpp b/libs/ipc/service.hpp index 8f6f62b..5b6297c 100644 --- a/libs/ipc/service.hpp +++ b/libs/ipc/service.hpp @@ -130,7 +130,7 @@ public: std::shared_ptr callSync(const MethodID methodID, const PeerID peerID, const std::shared_ptr& data, - unsigned int timeoutMS = 500); + unsigned int timeoutMS = 5000); /** * Asynchronous method call. The return callback will be called on -- 2.7.4 From 8de79321e3f62336cf2cdbd72ee355ae0af4bf22 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Wed, 6 May 2015 12:16:49 +0200 Subject: [PATCH 02/16] Remove libcap_ng and replace it with syscalls [Feature] libcap_ng is removed [Cause] N/A [Solution] Replace libcap_ng with syscalls [Verification] Build, install, run vasum-server without root and check if all needed capabilities were kept by the process. Change-Id: Idab4c7b579c6541d941e8c9e9c792427428f8fe5 --- client/CMakeLists.txt | 2 +- common/utils/environment.cpp | 206 ++++++++++++++++++++++++++++++++++++++-- common/utils/environment.hpp | 2 +- packaging/vasum.spec | 1 - server/CMakeLists.txt | 2 +- server/server.cpp | 2 +- tests/unit_tests/CMakeLists.txt | 2 +- zone-daemon/CMakeLists.txt | 2 +- 8 files changed, 202 insertions(+), 17 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c1fdd19..c9f4c17 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -44,7 +44,7 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) -PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libcap-ng) +PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp index 57b6e2a..9614cfa 100644 --- a/common/utils/environment.cpp +++ b/common/utils/environment.cpp @@ -31,7 +31,6 @@ #include "base-exception.hpp" #include "logger/logger.hpp" -#include #include #include #include @@ -42,12 +41,15 @@ #include #include #include +#include #include #include +#include +#include +#include -#if !__GLIBC_PREREQ(2, 14) -#include +#if !__GLIBC_PREREQ(2, 14) #ifdef __NR_setns static inline int setns(int fd, int nstype) @@ -61,10 +63,37 @@ static inline int setns(int fd, int nstype) #endif +#ifdef __NR_capset +static inline int capset(cap_user_header_t header, const cap_user_data_t data) +{ + return syscall(__NR_capset, header, data); +} +#else +#error "capset syscall isn't available" +#endif + +#ifdef __NR_capget +static inline int capget(cap_user_header_t header, cap_user_data_t data) +{ + return syscall(__NR_capget, header, data); +} +#else +#error "capget syscall isn't available" +#endif + using namespace utils; namespace { +#define CAP_SET_INHERITABLE (1 << 0) +#define CAP_SET_PERMITTED (1 << 1) +#define CAP_SET_EFFECTIVE (1 << 2) + +// number of __user_cap_data_struct elements needed +#define CAP_DATA_ELEMENT_COUNT 2 + +typedef unsigned int CapSet; + const std::map NAMESPACES = { {CLONE_NEWIPC, "ipc"}, {CLONE_NEWNET, "net"}, @@ -125,6 +154,75 @@ bool fdSend(int socket, int fd) return true; } +inline bool isValidCap(unsigned int cap) +{ + return cap <= CAP_LAST_CAP; +} + +// hasCap assumes that "set" variable will refer to only one set of capabilities +inline bool hasCap(unsigned int cap, const cap_user_data_t data, CapSet set) +{ + // calculate which half of data we need to update + int dataInd = 0; + if (cap > 31) { + dataInd = cap >> 5; + cap %= 32; + } + + switch (set) { + case CAP_SET_INHERITABLE: + return CAP_TO_MASK(cap) & data[dataInd].inheritable ? true : false; + case CAP_SET_PERMITTED: + return CAP_TO_MASK(cap) & data[dataInd].permitted ? true : false; + case CAP_SET_EFFECTIVE: + return CAP_TO_MASK(cap) & data[dataInd].effective ? true : false; + default: + return false; + }; +} + +// these inlines work in-place and update provided "data" array +// in these inlines, "set" can refer to mulitple sets of capabilities +inline void addCap(unsigned int cap, cap_user_data_t data, CapSet set) +{ + // calculate which half of data we need to update + int dataInd = 0; + if (cap > 31) { + dataInd = cap >> 5; + cap %= 32; + } + + if ((set & CAP_SET_INHERITABLE) == CAP_SET_INHERITABLE) { + data[dataInd].inheritable |= CAP_TO_MASK(cap); + } + if ((set & CAP_SET_PERMITTED) == CAP_SET_PERMITTED) { + data[dataInd].permitted |= CAP_TO_MASK(cap); + } + if ((set & CAP_SET_EFFECTIVE) == CAP_SET_EFFECTIVE) { + data[dataInd].effective |= CAP_TO_MASK(cap); + } +} + +inline void removeCap(unsigned int cap, cap_user_data_t data, CapSet set) +{ + // calculate which half of data we need to update + int dataInd = 0; + if (cap > 31) { + dataInd = cap >> 5; + cap %= 32; + } + + if ((set & CAP_SET_INHERITABLE) == CAP_SET_INHERITABLE) { + data[dataInd].inheritable &= ~(CAP_TO_MASK(cap)); + } + if ((set & CAP_SET_PERMITTED) == CAP_SET_PERMITTED) { + data[dataInd].permitted &= ~(CAP_TO_MASK(cap)); + } + if ((set & CAP_SET_EFFECTIVE) == CAP_SET_EFFECTIVE) { + data[dataInd].effective &= ~(CAP_TO_MASK(cap)); + } +} + } // namespace namespace utils { @@ -156,19 +254,107 @@ bool setSuppGroups(const std::vector& groups) bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps) { - ::capng_clear(CAPNG_SELECT_BOTH); + ::__user_cap_header_struct header; + ::__user_cap_data_struct data[CAP_DATA_ELEMENT_COUNT]; + + // initial setup - equivalent to capng_clear + header.version = _LINUX_CAPABILITY_VERSION_3; + header.pid = ::getpid(); + memset(data, 0, CAP_DATA_ELEMENT_COUNT*sizeof(__user_cap_data_struct)); + // update cap sets - equivalent to capng_update for (const auto cap : caps) { - if (::capng_update(CAPNG_ADD, static_cast(CAPNG_EFFECTIVE | - CAPNG_PERMITTED | - CAPNG_INHERITABLE), cap)) { - LOGE("Failed to set capability: " << ::capng_capability_to_name(cap)); + if (!isValidCap(cap)) { + LOGE("Capability " << cap << " is invalid."); return false; } + + addCap(cap, data, CAP_SET_INHERITABLE | CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); } - if (::capng_change_id(uid, gid, static_cast(CAPNG_CLEAR_BOUNDING))) { - LOGE("Failed to change process user"); + // perform some checks and cap updates + bool updatedSetUid, updatedSetGid; + // check if we are capable of switching our UID + if (hasCap(CAP_SETUID, data, CAP_SET_EFFECTIVE)) { + // we want to keep CAP_SETUID after change + updatedSetUid = false; + } else { + // we don't have CAP_SETUID and switch is needed - add SETUID to effective and permitted set + updatedSetUid = true; + addCap(CAP_SETUID, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + } + + // do the same routine for CAP_SETGID + if (hasCap(CAP_SETGID, data, CAP_SET_EFFECTIVE)) { + updatedSetGid = false; + } else { + updatedSetGid = true; + addCap(CAP_SETGID, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + } + + // we need CAP_SETPCAP as well to clear bounding caps + if (!hasCap(CAP_SETPCAP, data, CAP_SET_EFFECTIVE)) { + addCap(CAP_SETPCAP, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + } + + // now we can work - first, use prctl to tell system we want to keep our caps when changing UID + if (::prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { + LOGE("prctl failed while trying to enable keepcaps: " << strerror(errno)); + return false; + } + + LOGD("Setting temporary caps to process -" << std::hex << std::setfill('0') + << " inh:" << std::setw(8) << data[1].inheritable << std::setw(8) << data[0].inheritable + << " prm:" << std::setw(8) << data[1].permitted << std::setw(8) << data[0].permitted + << " eff:" << std::setw(8) << data[1].effective << std::setw(8) << data[0].effective); + + // set our modified caps before UID/GID change + if (::capset(&header, data)) { + LOGE("capset failed: " << strerror(errno)); + return false; + } + + // CAP_SETPCAP is available, drop bounding caps + for (int i = 0; i <= CAP_LAST_CAP; ++i) { + if (::prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) { + LOGE("prctl failed while dropping bounding caps: " << strerror(errno)); + return false; + } + } + + // set up GID and UID + if (::setresgid(gid, gid, gid)) { + LOGE("setresgid failed: " << strerror(errno)); + return false; + } + if (::setresuid(uid, uid, uid)) { + LOGE("setresuid failed: " << strerror(errno)); + return false; + } + + // we are after switch now - disable PR_SET_KEEPCAPS + if (::prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0)) { + LOGE("prctl failed while trying to disable keepcaps: " << strerror(errno)); + return false; + } + + // disable rendundant caps + if (updatedSetUid) { + removeCap(CAP_SETUID, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + } + if (updatedSetGid) { + removeCap(CAP_SETGID, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + } + removeCap(CAP_SETPCAP, data, CAP_SET_PERMITTED | CAP_SET_EFFECTIVE); + + LOGD("Setting final caps to process -" << std::hex << std::setfill('0') + << " inh:" << std::setw(8) << data[1].inheritable << std::setw(8) << data[0].inheritable + << " prm:" << std::setw(8) << data[1].permitted << std::setw(8) << data[0].permitted + << " eff:" << std::setw(8) << data[1].effective << std::setw(8) << data[0].effective); + + // finally, apply correct caps + if (::capset(&header, data)) { + LOGE("capset failed: " << strerror(errno)); return false; } diff --git a/common/utils/environment.hpp b/common/utils/environment.hpp index 9039239..8c99dd4 100644 --- a/common/utils/environment.hpp +++ b/common/utils/environment.hpp @@ -40,7 +40,7 @@ namespace utils { bool setSuppGroups(const std::vector& groups); /** - * Set effective and permited capabilities on the current process and drop root privileges. + * Set effective and permitted capabilities on the current process and drop root privileges. */ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps); diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 3b241df..82a859e 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -20,7 +20,6 @@ Summary: Daemon for managing zones BuildRequires: cmake BuildRequires: boost-devel BuildRequires: libjson-devel >= 0.10 -BuildRequires: libcap-ng-devel BuildRequires: lxc-devel BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(sqlite3) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index f9ce867..9a1985c 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -30,7 +30,7 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) -PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0 libcap-ng) +PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) diff --git a/server/server.cpp b/server/server.cpp index 95f22a0..936db28 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -42,10 +42,10 @@ #include #include #include -#include #include #include #include +#include #ifndef VASUM_USER diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 2b5a09e..484e810 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -47,7 +47,7 @@ ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS} ${clie ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) -PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0 libcap-ng) +PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER} ${LIBS_FOLDER} ${SOCKET_TEST_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt index 4d48141..4944dfb 100644 --- a/zone-daemon/CMakeLists.txt +++ b/zone-daemon/CMakeLists.txt @@ -31,7 +31,7 @@ ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) -PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0 libcap-ng) +PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) -- 2.7.4 From 9bc344d7c4b3e6b73aeabef1488393c409796490 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Mon, 25 May 2015 13:13:32 +0200 Subject: [PATCH 03/16] Vasum wrapper #8: implement socket related functions, obsolete vasum-daemon [Bug/Feature] socket not opens, rpm install conflict [Cause] N/A [Solution] #8 implement socket creation, etc. [Verification] Build, install on target, check journal Change-Id: I2c6dd5e40a08bda3722167c4e1f06b60bb53e7dc --- packaging/vasum.spec | 1 + wrapper/CMakeLists.txt | 3 +- wrapper/wrapper-compatibility.cpp | 216 +++++++++++++++++++++++++++++++++++--- wrapper/wrapper.cpp | 5 +- 4 files changed, 206 insertions(+), 19 deletions(-) diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 82a859e..8f10a1c 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -26,6 +26,7 @@ BuildRequires: pkgconfig(sqlite3) Requires(post): libcap-tools Requires: iproute2 Requires: libjson >= 0.10 +Obsoletes: vasum-daemon < 1:0 %description This package provides a daemon used to manage zones - start, stop and switch diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt index a75bfa9..a8aa173 100644 --- a/wrapper/CMakeLists.txt +++ b/wrapper/CMakeLists.txt @@ -42,6 +42,7 @@ SET(PC_FILE "${PROJECT_NAME}.pc") ## libraries, produce more optimized code, provide near-perfect API export ## and prevent symbol clashes ADD_DEFINITIONS(-fvisibility=hidden) +ADD_DEFINITIONS(-D__STDC_FORMAT_MACROS) ADD_LIBRARY(${PROJECT_NAME} SHARED ${wrapper_SRCS} ${common_SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES @@ -51,7 +52,7 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) -PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libcap-ng) +PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) diff --git a/wrapper/wrapper-compatibility.cpp b/wrapper/wrapper-compatibility.cpp index 303fcfe..942c5f6 100644 --- a/wrapper/wrapper-compatibility.cpp +++ b/wrapper/wrapper-compatibility.cpp @@ -32,16 +32,18 @@ #include #include #include +#include +#include +#include +#include //PRIx64 #include #include #include #include #include -#include -#include -#include #include #include +#include #include "logger/logger.hpp" #include "logger/logger-scope.hpp" @@ -62,43 +64,227 @@ API pid_t get_domain_pid(const char * /*name*/, const char * /*target*/) { } // sock_close_socket -API int sock_close_socket(int /*fd*/) { +API int sock_close_socket(int fd) { LOGS(""); + struct sockaddr_un addr; + socklen_t addrlen = sizeof(addr); + + if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) && addr.sun_path[0]) { + unlink(addr.sun_path); + } + + close(fd); + return 0; } // sock_connect -API int sock_connect(const char * /*path*/) { +API int sock_connect(const char *path) { LOGS(""); - return -1; + size_t len; + int fd, idx = 0; + struct sockaddr_un addr; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + + addr.sun_family = AF_UNIX; + + /* Is it abstract address */ + if (path[0] == '\0') { + idx++; + } + LOGD("socket path=" << &path[idx]); + len = strlen(&path[idx]) + idx; + if (len >= sizeof(addr.sun_path)) { + close(fd); + errno = ENAMETOOLONG; + return -1; + } + + strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx])); + if (connect + (fd, (struct sockaddr *)&addr, + offsetof(struct sockaddr_un, sun_path) + len)) { + close(fd); + return -1; + } + + return fd; } + // sock_create_socket -API int sock_create_socket(const char * /*path*/, int /*type*/, int /*flags*/) { +API int sock_create_socket(const char *path, int type, int flags) { LOGS(""); - return -1; + size_t len; + int fd, idx = 0; + struct sockaddr_un addr; + + if (!path) + return -1; + + if (flags & O_TRUNC) + unlink(path); + + fd = socket(PF_UNIX, type, 0); + if (fd < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + + addr.sun_family = AF_UNIX; + + /* Is it abstract address */ + if (path[0] == '\0') { + idx++; + } + LOGD("socket path=" << &path[idx]); + len = strlen(&path[idx]) + idx; + if (len >= sizeof(addr.sun_path)) { + close(fd); + errno = ENAMETOOLONG; + return -1; + } + + strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx])); + + if (bind (fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len)) { + close(fd); + return -1; + } + + if (type == SOCK_STREAM && listen(fd, 100)) { + close(fd); + return -1; + } + + return fd; } + +// "Fowler–Noll–Vo hash function" implementation (taken from old API source) +#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) +static uint64_t hash_fnv_64a(void *buf, size_t len, uint64_t hval) +{ + unsigned char *bp; + + for (bp = (unsigned char *)buf; bp < (unsigned char *)buf + len; bp++) { + hval ^= (uint64_t) * bp; + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); + } + + return hval; +} + // sock_monitor_address -API int sock_monitor_address(char * /*buffer*/, int /*len*/, const char * /*lxcpath*/) { +API int sock_monitor_address(char *buffer, int len, const char *lxcpath) { LOGS(""); + int ret; + uint64_t hash; + char *sockname; + char path[PATH_MAX]; + + memset(buffer, 0, len); + sockname = &buffer[1]; + + ret = snprintf(path, sizeof(path), "lxc/%s/monitor-sock", lxcpath); + if (ret < 0) { + errno = ENAMETOOLONG; + return -1; + } + + hash = hash_fnv_64a(path, ret, FNV1A_64_INIT); + ret = snprintf(sockname, len, "lxc/%016" PRIx64 "/%s", hash, lxcpath); + if (ret < 0) { + errno = ENAMETOOLONG; + return -1; + } + return 0; } // sock_recv_fd (intern) -API int sock_recv_fd(int /*fd*/, int * /*recvfd*/, void * /*data*/, size_t /*size*/) { +API int sock_recv_fd(int fd, int *recvfd, void *data, size_t size) { LOGS(""); - return 0; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + char buf[1]; + int ret, *val; + + 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_iov = &iov; + msg.msg_iovlen = 1; + + ret = recvmsg(fd, &msg, 0); + if (ret <= 0) + goto out; + + 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; + } + out: + return ret; + } // sock_send_fd -API int sock_send_fd(int /*fd*/, int /*sendfd*/, void * /*data*/, size_t /*size*/) { +API int sock_send_fd(int fd, int sendfd, void *data, size_t size) { LOGS(""); - return 0; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + char buf[1]; + int *val; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + 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; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + iov.iov_base = data ? data : buf; + iov.iov_len = data ? size : sizeof(buf); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + return sendmsg(fd, &msg, MSG_NOSIGNAL); } // vasum_log API void vasum_log(int type, const char *tag, const char *fmt, ...) { va_list arg_ptr; - char buf[100]; + char buf[255]; + LOGS("type=" << type << " tag=" << tag); va_start(arg_ptr, fmt); vsnprintf(buf, sizeof(buf), fmt, arg_ptr); va_end(arg_ptr); - LOGS("type=" << type << " tag=" << tag << " msg=" << buf); + buf[sizeof(buf)-1]=0; + LOGD("msg=" << buf); } #define MAX_ERROR_MSG 0x1000 diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 4fc0c60..5623263 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -668,6 +668,7 @@ API int vsm_is_host_zone(vsm_zone_h zone) if (zone == NULL) return -VSM_ERROR_INVALID; + LOGI("zone->parent == zone is " << (zone->parent == zone ? 1 : 0)); return zone->parent == zone ? 1 : 0; } API vsm_zone_h vsm_join_zone(vsm_zone_h /*zone*/) @@ -683,9 +684,7 @@ API int vsm_canonicalize_path(const char *input_path, char **output_path) return len; } -// Note: incomaptible API, support newer -// API(v0.34) const char *vsm_error_string(struct vsm_context *ctx) -// API(v0.3.1) const char *vsm_error_string(vsm_error_e error) +// Note: support the newer API (incomaptible with older) API const char *vsm_error_string(vsm_error_e error) { LOGS(""); -- 2.7.4 From 8312cde30ab9a4aa689d34fce39f573cdeca8712 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 27 May 2015 15:30:33 +0200 Subject: [PATCH 04/16] Fix configuration script permissions [Feature] N/A [Cause] N/A [Solution] LXC templates have x permission [Verification] Build, run all tests Change-Id: I6a2486a588f8a28dfe84f187a4889f0f9500e2a6 --- server/configs/CMakeLists.txt | 9 ++++++--- tests/unit_tests/configs/CMakeLists.txt | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 0e7be41..278a9fc 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -19,8 +19,8 @@ MESSAGE(STATUS "Installing configs to " ${VSM_CONFIG_INSTALL_DIR}) -FILE(GLOB template_CONF templates/*.conf - templates/*.sh) +FILE(GLOB zone_templates_CONF templates/*.conf) +FILE(GLOB lxc_templates_CONF templates/*.sh) ## Generate #################################################################### CONFIGURE_FILE(systemd/vasum.service.in @@ -43,7 +43,10 @@ INSTALL(FILES ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.vasum.host.con INSTALL(DIRECTORY DESTINATION ${VSM_CONFIG_INSTALL_DIR}/zones) #TODO temporary solution -INSTALL(PROGRAMS ${template_CONF} +INSTALL(FILES ${zone_templates_CONF} + DESTINATION ${VSM_CONFIG_INSTALL_DIR}/templates) + +INSTALL(PROGRAMS ${lxc_templates_CONF} DESTINATION ${VSM_CONFIG_INSTALL_DIR}/templates) INSTALL(FILES diff --git a/tests/unit_tests/configs/CMakeLists.txt b/tests/unit_tests/configs/CMakeLists.txt index 04aabda..a18914e 100644 --- a/tests/unit_tests/configs/CMakeLists.txt +++ b/tests/unit_tests/configs/CMakeLists.txt @@ -20,8 +20,8 @@ MESSAGE(STATUS "Installing configs for the Unit Tests to " ${VSM_TEST_CONFIG_INSTALL_DIR}) FILE(GLOB ut_zone_CONF *.conf) -FILE(GLOB ut_zone_templates_CONF templates/*.conf - templates/*.sh) +FILE(GLOB ut_zone_templates_CONF templates/*.conf) +FILE(GLOB ut_lxc_templates_CONF templates/*.sh) ## Generate #################################################################### CONFIGURE_FILE(test-daemon.conf.in @@ -44,6 +44,9 @@ INSTALL(FILES ${ut_zone_templates_CONF} ${ut_zone_templates_CONF_GEN} DESTINATION ${VSM_TEST_TEMPLATES_INSTALL_DIR}) +INSTALL(PROGRAMS ${ut_lxc_templates_CONF} + DESTINATION ${VSM_TEST_TEMPLATES_INSTALL_DIR}) + INSTALL(FILES dbus/ut-dbus.conf dbus/ut-dbus-system.conf DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/dbus) -- 2.7.4 From bdad02ae0c2da1eeeabbd3f96185a09aa964d8ce Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 27 May 2015 18:48:47 +0200 Subject: [PATCH 05/16] Small documentation for github [Feature] N/A [Cause] N/A [Solution] N/A [Verification] N/A Change-Id: Ia7beba020ae92619e3639ee70af65794d2b662a1 --- README | 18 ------------------ README.md | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index d194922..0000000 --- a/README +++ /dev/null @@ -1,18 +0,0 @@ -# Documentation - -Generate documentation by executing command generate_documentation.sh -from doc directory. Documentation will be generated in doc/html directory. -There is also GUI tool named doxywizard. - - cd ./doc - ./generate_documentation.sh - - -# Code formatting - -We use astyle for code formatting. -Get the latest version from http://sourceforge.net/projects/astyle/files/astyle/ -(at least v2.04). You can find the options file in the root of the project. -For example to format all .cpp and .hpp files run in the project directory: - - astyle --options=./astylerc --recursive ./*.cpp ./*.hpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ccd43c --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Vasum +[Vasum](https://wiki.tizen.org/wiki/Security:Vasum) is a Linux daemon and a set of utilities used for managing para-virtualization. It uses Linux Containers to create separate, graphical environments called *zones*. One can concurrently run several zones on one physical device. Vasum exports a rich C/Dbus API that the application frameworks can use to interact with zones. + +For now Vasum uses [LXC](https://linuxcontainers.org/lxc/introduction/) for Linux Containers management. The project is mostly written in modern C++, is [well tested](https://wiki.tizen.org/wiki/Weekly_test_results_for_Tizen_3.X_security_framework). + +Vasum's development takes place on [review.tizen.org/gerrit/](http://review.tizen.org/gerrit/) (registration on [tizen.org](http://tizen.org) is required). + +## Installation and usage +The installation process and simple verification is described [here](https://wiki.tizen.org/wiki/Security:Vasum:Usage). + +## Client interface +Vasum daemon can be accessed via C API or Dbus. You can find the API documentation [here](https://wiki.tizen.org/wiki/Security:Vasum:API). Be aware that the API will most likely change in the near future. + +## Documentation +More comprehensive documentation is kept [here](https://wiki.tizen.org/wiki/Security:Vasum). You can generate the code documentation by executing *generate_documentation.sh* script from *doc* directory. Documentation will be generated in doc/html directory. + + cd ./doc + ./generate_documentation.sh + + +## Code formatting +We use [astyle](http://astyle.sourceforge.net/) for code formatting (Use the latest version) +You can find the options file in the root of the project. + +For example to format all .cpp and .hpp files run in the project directory: + + astyle --options=./astylerc --recursive ./*.cpp ./*.hpp \ No newline at end of file -- 2.7.4 From 7c6e79b69e1a39c1c033ffb4891ec3ca21e4f309 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Tue, 2 Jun 2015 14:16:43 +0200 Subject: [PATCH 06/16] Removed Glib connected functions from API [Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, run all tests Change-Id: I3fe5e789535fcb53ee5d223172cb63bd44fb962c --- cli/command-line-interface.cpp | 6 ------ client/vasum-client-impl.cpp | 12 ------------ client/vasum-client-impl.hpp | 9 --------- client/vasum-client.cpp | 11 ----------- client/vasum-client.h | 25 ------------------------- wrapper/wrapper.cpp | 5 ----- 6 files changed, 68 deletions(-) diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index 2ae3778..2393ce1 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -58,11 +58,6 @@ void one_shot(const function& fun) VsmStatus status; VsmClient client; - status = vsm_start_glib_loop(); - if (VSMCLIENT_SUCCESS != status) { - throw runtime_error("Can't start glib loop"); - } - client = vsm_client_create(); if (NULL == client) { msg = "Can't create client"; @@ -83,7 +78,6 @@ void one_shot(const function& fun) finish: vsm_client_free(client); - vsm_stop_glib_loop(); if (! msg.empty()) { throw runtime_error(msg); } diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index 38e4c5a..f87e9a0 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -127,18 +127,6 @@ bool readFirstLineOfFile(const string& path, string& ret) } //namespace -VsmStatus Client::vsm_start_glib_loop() noexcept -{ - // TPDP: Remove vsm_start_glib_loop from API - return VSMCLIENT_SUCCESS; -} - -VsmStatus Client::vsm_stop_glib_loop() noexcept -{ - // TPDP: Remove vsm_stop_glib_loop from API - return VSMCLIENT_SUCCESS; -} - Client::Status::Status() : mVsmStatus(VSMCLIENT_SUCCESS), mMsg() { diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 86f7a5e..5a1d2fd 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -336,15 +336,6 @@ public: */ VsmStatus vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept; - /** - * @see ::vsm_start_glib_loop - */ - static VsmStatus vsm_start_glib_loop() noexcept; - - /** - * @see ::vsm_stop_glib_loop - */ - static VsmStatus vsm_stop_glib_loop() noexcept; private: typedef vasum::client::HostIPCConnection HostConnection; struct Status { diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index b1028e2..1d5664c 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -45,17 +45,6 @@ Client& getClient(VsmClient client) } // namespace -/* external */ -API VsmStatus vsm_start_glib_loop() -{ - return Client::vsm_start_glib_loop(); -} - -API VsmStatus vsm_stop_glib_loop() -{ - return Client::vsm_stop_glib_loop(); -} - API VsmClient vsm_client_create() { Client* clientPtr = new(nothrow) Client(); diff --git a/client/vasum-client.h b/client/vasum-client.h index 6c68fe2..7a98fa7 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -34,12 +34,6 @@ int main(int argc, char** argv) VsmArrayString values = NULL; int ret = 0; - status = vsm_start_glib_loop(); // start glib loop (if not started any yet) - if (VSMCLIENT_SUCCESS != status) { - // error! - return 1; - } - client = vsm_client_create(); // create client handle if (NULL == client) { // error! @@ -69,7 +63,6 @@ int main(int argc, char** argv) finish: vsm_array_string_free(values); // free memory vsm_client_free(client); // destroy client handle - vsm_stop_glib_loop(); // stop the glib loop (use only with vsm_start_glib_loop) return ret; } @endcode @@ -188,24 +181,6 @@ typedef enum { } VsmFileType; #ifndef __VASUM_WRAPPER_SOURCE__ -/** - * Start glib loop. - * - * Do not call this function if an application creates a glib loop itself. - * Otherwise, call it before any other function from this library. - * - * @return status of this function call - */ -VsmStatus vsm_start_glib_loop(); - -/** - * Stop glib loop. - * - * Call only if vsm_start_glib_loop() was called. - * - * @return status of this function call - */ -VsmStatus vsm_stop_glib_loop(); /** * Create a new vasum-server's client. diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 5623263..8b890cf 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -54,7 +54,6 @@ struct WrappedContext static struct { int done; - int glib_stop; } wrap; @@ -90,8 +89,6 @@ void wrapper_load(void) void wrapper_unload(void) { - if (wrap.glib_stop) Client::vsm_stop_glib_loop(); - wrap.glib_stop = 0; LOGI("wrapper_unload"); } @@ -153,8 +150,6 @@ static int wrap_error(VsmStatus st, const Client *c) static void init_context_wrap(WrappedContext *w) { - Client::vsm_start_glib_loop(); - wrap.glib_stop = 1; w->client = new Client(); VsmStatus st = w->client->createSystem(); wrap_error(st, w->client); -- 2.7.4 From 1c1c682dacd05c0824d4fcf7d18b95eeff20cfc4 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Mon, 1 Jun 2015 16:11:54 +0200 Subject: [PATCH 07/16] File descriptor passing via IPC [Feature] FD passing via Unix socket [Cause] N/A [Solution] N/A [Verification] Build, run all tests Change-Id: I1683a7e99a104d5dbdd5c0c56913753c9bdd3cf2 --- libs/config/fdstore.cpp | 178 +++++++++++++++++++++++++++++++---- libs/config/fdstore.hpp | 12 ++- libs/config/fields.hpp | 2 + libs/config/from-fdstore-visitor.hpp | 6 ++ libs/config/to-fdstore-visitor.hpp | 6 ++ libs/config/types.hpp | 44 +++++++++ libs/ipc/internals/socket.cpp | 10 +- libs/ipc/internals/socket.hpp | 4 +- tests/unit_tests/ipc/ut-ipc.cpp | 60 +++++++++++- 9 files changed, 291 insertions(+), 31 deletions(-) create mode 100644 libs/config/types.hpp diff --git a/libs/config/fdstore.cpp b/libs/config/fdstore.cpp index c0b7d08..cc0b903 100644 --- a/libs/config/fdstore.cpp +++ b/libs/config/fdstore.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace config { @@ -102,24 +103,28 @@ FDStore::~FDStore() void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS) { - std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() + - std::chrono::milliseconds(timeoutMS); + std::chrono::high_resolution_clock::time_point deadline = + std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); size_t nTotal = 0; for (;;) { - int n = ::write(mFD, - reinterpret_cast(bufferPtr) + nTotal, - size - nTotal); - if (n >= 0) { + ssize_t n = ::write(mFD, + reinterpret_cast(bufferPtr) + nTotal, + size - nTotal); + if (n < 0) { + // Handle errors + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors + } else { + throw ConfigException("Error during writing: " + getSystemErrorMessage()); + } + } else { nTotal += n; if (nTotal == size) { - // All data is written, break loop + // All data is read, break loop break; } - } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - // Neglected errors - } else { - throw ConfigException("Error during writing: " + getSystemErrorMessage()); } waitForEvent(mFD, POLLOUT, deadline); @@ -128,15 +133,23 @@ void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeoutMS) { - std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() + - std::chrono::milliseconds(timeoutMS); + std::chrono::high_resolution_clock::time_point deadline = + std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); size_t nTotal = 0; for (;;) { - int n = ::read(mFD, - reinterpret_cast(bufferPtr) + nTotal, - size - nTotal); - if (n >= 0) { + ssize_t n = ::read(mFD, + reinterpret_cast(bufferPtr) + nTotal, + size - nTotal); + if (n < 0) { + // Handle errors + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors + } else { + throw ConfigException("Error during reading: " + getSystemErrorMessage()); + } + } else { nTotal += n; if (nTotal == size) { // All data is read, break loop @@ -145,13 +158,138 @@ void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeou if (n == 0) { throw ConfigException("Peer disconnected"); } - } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - // Neglected errors + } + + waitForEvent(mFD, POLLIN, deadline); + } +} + + +void FDStore::sendFD(int fd, const unsigned int timeoutMS) +{ + std::chrono::high_resolution_clock::time_point deadline = + std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); + + // Space for the file descriptor + union { + struct cmsghdr cmh; + char control[CMSG_SPACE(sizeof(int))]; + } controlUnion; + + // Ensure at least 1 byte is transmited via the socket + struct iovec iov; + char buf = '!'; + iov.iov_base = &buf; + iov.iov_len = sizeof(char); + + // Fill the message to send: + // The socket has to be connected, so we don't need to specify the name + struct msghdr msgh; + ::memset(&msgh, 0, sizeof(msgh)); + + // Only iovec to transmit one element + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + + // Ancillary data buffer + msgh.msg_control = controlUnion.control; + msgh.msg_controllen = sizeof(controlUnion.control); + + // Describe the data that we want to send + struct cmsghdr *cmhp; + cmhp = CMSG_FIRSTHDR(&msgh); + cmhp->cmsg_len = CMSG_LEN(sizeof(int)); + cmhp->cmsg_level = SOL_SOCKET; + cmhp->cmsg_type = SCM_RIGHTS; + *(reinterpret_cast(CMSG_DATA(cmhp))) = fd; + + // Send + for(;;) { + ssize_t ret = ::sendmsg(mFD, &msgh, MSG_NOSIGNAL); + if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors, retry + } else { + throw ConfigException("Error during sendmsg: " + getSystemErrorMessage()); + } + } else if (ret == 0) { + // Retry the sending } else { - throw ConfigException("Error during reading: " + getSystemErrorMessage()); + // We send only 1 byte of data. No need to repeat + break; + } + + waitForEvent(mFD, POLLOUT, deadline); + } +} + + +int FDStore::receiveFD(const unsigned int timeoutMS) +{ + std::chrono::high_resolution_clock::time_point deadline = + std::chrono::high_resolution_clock::now() + + std::chrono::milliseconds(timeoutMS); + + // Space for the file descriptor + union { + struct cmsghdr cmh; + char control[CMSG_SPACE(sizeof(int))]; + } controlUnion; + + // Describe the data that we want to recive + controlUnion.cmh.cmsg_len = CMSG_LEN(sizeof(int)); + controlUnion.cmh.cmsg_level = SOL_SOCKET; + controlUnion.cmh.cmsg_type = SCM_RIGHTS; + + // Setup the input buffer + // Ensure at least 1 byte is transmited via the socket + char buf; + struct iovec iov; + iov.iov_base = &buf; + iov.iov_len = sizeof(char); + + // Set the ancillary data buffer + // The socket has to be connected, so we don't need to specify the name + struct msghdr msgh; + ::memset(&msgh, 0, sizeof(msgh)); + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + + msgh.msg_control = controlUnion.control; + msgh.msg_controllen = sizeof(controlUnion.control); + + // Receive + for(;;) { + ssize_t ret = ::recvmsg(mFD, &msgh, MSG_WAITALL); + if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + // Neglected errors, retry + } else { + throw ConfigException("Error during recvmsg: " + getSystemErrorMessage()); + } + } else if (ret == 0) { + throw ConfigException("Peer disconnected"); + } else { + // We receive only 1 byte of data. No need to repeat + break; } waitForEvent(mFD, POLLIN, deadline); } + + struct cmsghdr *cmhp; + cmhp = CMSG_FIRSTHDR(&msgh); + if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(int))) { + throw ConfigException("Bad cmsg length"); + } else if (cmhp->cmsg_level != SOL_SOCKET) { + throw ConfigException("cmsg_level != SOL_SOCKET"); + } else if (cmhp->cmsg_type != SCM_RIGHTS) { + throw ConfigException("cmsg_type != SCM_RIGHTS"); + } + + return *(reinterpret_cast(CMSG_DATA(cmhp))); } + } // namespace config diff --git a/libs/config/fdstore.hpp b/libs/config/fdstore.hpp index d76fc5f..d6e30aa 100644 --- a/libs/config/fdstore.hpp +++ b/libs/config/fdstore.hpp @@ -27,6 +27,10 @@ #include +namespace { +const unsigned int maxTimeout = 5000; +} // namespace + namespace config { class FDStore { @@ -50,7 +54,7 @@ public: * @param size size of the buffer * @param timeoutMS timeout in milliseconds */ - void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 5000); + void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = maxTimeout); /** * Reads a value of the given type. @@ -59,7 +63,11 @@ public: * @param size size of the buffer * @param timeoutMS timeout in milliseconds */ - void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 5000); + void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = maxTimeout); + + void sendFD(int fd, const unsigned int timeoutMS = maxTimeout); + + int receiveFD(const unsigned int timeoutMS = maxTimeout); private: int mFD; diff --git a/libs/config/fields.hpp b/libs/config/fields.hpp index cba5a67..8169cb4 100644 --- a/libs/config/fields.hpp +++ b/libs/config/fields.hpp @@ -28,6 +28,8 @@ #include #include +#include "config/types.hpp" + #if BOOST_PP_VARIADICS != 1 #error variadic macros not supported #endif diff --git a/libs/config/from-fdstore-visitor.hpp b/libs/config/from-fdstore-visitor.hpp index 9b9df42..3863f7f 100644 --- a/libs/config/from-fdstore-visitor.hpp +++ b/libs/config/from-fdstore-visitor.hpp @@ -27,6 +27,7 @@ #include "config/is-visitable.hpp" #include "config/fdstore.hpp" +#include "config/types.hpp" #include @@ -60,6 +61,11 @@ private: mStore.read(&value.front(), size); } + void readInternal(config::FileDescriptor& fd) + { + fd = mStore.receiveFD(); + } + template::value, int>::type = 0> void readInternal(T& value) { diff --git a/libs/config/to-fdstore-visitor.hpp b/libs/config/to-fdstore-visitor.hpp index 50756c1..1eedddb 100644 --- a/libs/config/to-fdstore-visitor.hpp +++ b/libs/config/to-fdstore-visitor.hpp @@ -27,6 +27,7 @@ #include "config/is-visitable.hpp" #include "config/fdstore.hpp" +#include "config/types.hpp" #include @@ -59,6 +60,11 @@ private: mStore.write(value.c_str(), value.size()); } + void writeInternal(const config::FileDescriptor& fd) + { + mStore.sendFD(fd.value); + } + template::value, int>::type = 0> void writeInternal(const T& value) { diff --git a/libs/config/types.hpp b/libs/config/types.hpp new file mode 100644 index 0000000..3355f8f --- /dev/null +++ b/libs/config/types.hpp @@ -0,0 +1,44 @@ +/* + * 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 Types declarations + */ + +#ifndef COMMON_CONFIG_TYPES_HPP +#define COMMON_CONFIG_TYPES_HPP + +namespace config { + +/** + * Whenever possible, this type will be serialized using Linux file descriptor passing. + */ +struct FileDescriptor { + int value; + FileDescriptor(int fd = -1): value(fd) {} + FileDescriptor& operator=(const int fd) { + value = fd; + return *this; + } +}; + +}// config + +#endif //COMMON_CONFIG_TYPES_HPP \ No newline at end of file diff --git a/libs/ipc/internals/socket.cpp b/libs/ipc/internals/socket.cpp index 0654a4e..690bd43 100644 --- a/libs/ipc/internals/socket.cpp +++ b/libs/ipc/internals/socket.cpp @@ -56,7 +56,7 @@ void setFdOptions(int fd) } } -} +} // namespace Socket::Socket(int socketFD) : mFD(socketFD) @@ -112,7 +112,7 @@ void Socket::read(void* bufferPtr, const size_t size) const utils::read(mFD, bufferPtr, size); } -int Socket::getSystemdSocket(const std::string& path) +int Socket::getSystemdSocketInternal(const std::string& path) { int n = ::sd_listen_fds(-1 /*Block further calls to sd_listen_fds*/); if (n < 0) { @@ -132,7 +132,7 @@ int Socket::getSystemdSocket(const std::string& path) return -1; } -int Socket::createZoneSocket(const std::string& path) +int Socket::createSocketInternal(const std::string& path) { // Isn't the path too long? if (path.size() >= sizeof(sockaddr_un::sun_path)) { @@ -178,8 +178,8 @@ int Socket::createZoneSocket(const std::string& path) Socket Socket::createSocket(const std::string& path) { // Initialize a socket - int fd = getSystemdSocket(path); - fd = fd != -1 ? fd : createZoneSocket(path); + int fd = getSystemdSocketInternal(path); + fd = fd != -1 ? fd : createSocketInternal(path); return Socket(fd); } diff --git a/libs/ipc/internals/socket.hpp b/libs/ipc/internals/socket.hpp index 65f574d..c8f0a2d 100644 --- a/libs/ipc/internals/socket.hpp +++ b/libs/ipc/internals/socket.hpp @@ -108,8 +108,8 @@ private: int mFD; mutable std::recursive_mutex mCommunicationMutex; - static int createZoneSocket(const std::string& path); - static int getSystemdSocket(const std::string& path); + static int createSocketInternal(const std::string& path); + static int getSystemdSocketInternal(const std::string& path); }; } // namespace ipc diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 958f1f2..ab920fe 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -44,17 +44,24 @@ #include "config/fields.hpp" #include "logger/logger.hpp" +#include +#include #include #include #include #include #include #include +#include +#include +#include + using namespace ipc; using namespace epoll; using namespace utils; using namespace std::placeholders; +namespace fs = boost::filesystem; // Timeout for sending one message const int TIMEOUT = 1000 /*ms*/; @@ -67,6 +74,7 @@ const int LONG_OPERATION_TIME = 1000 + TIMEOUT; const std::string TEST_DIR = "/tmp/ut-ipc"; const std::string SOCKET_PATH = TEST_DIR + "/test.socket"; +const std::string TEST_FILE = TEST_DIR + "/file.txt"; struct FixtureBase { ScopedDir mTestPathGuard; @@ -80,14 +88,18 @@ struct FixtureBase { struct ThreadedFixture : FixtureBase { ThreadDispatcher dispatcher; - EventPoll& getPoll() { return dispatcher.getPoll(); } + EventPoll& getPoll() { + return dispatcher.getPoll(); + } }; struct GlibFixture : FixtureBase { ScopedGlibLoop glibLoop; GlibDispatcher dispatcher; - EventPoll& getPoll() { return dispatcher.getPoll(); } + EventPoll& getPoll() { + return dispatcher.getPoll(); + } }; struct SendData { @@ -110,6 +122,16 @@ struct RecvData { ) }; +struct FDData { + config::FileDescriptor fd; + FDData(int fd = -1): fd(fd) {} + + CONFIG_REGISTER + ( + fd + ) +}; + struct LongSendData { LongSendData(int i, int waitTime): mSendData(i), mWaitTime(waitTime), intVal(i) {} @@ -710,6 +732,40 @@ MULTI_FIXTURE_TEST_CASE(MixOperations, F, ThreadedFixture, GlibFixture) BOOST_CHECK(l.wait(TIMEOUT)); } +MULTI_FIXTURE_TEST_CASE(FDSendReceive, F, ThreadedFixture, GlibFixture) +{ + const char DATA[] = "Content of the file"; + { + // Fill the file + fs::remove(TEST_FILE); + std::ofstream file(TEST_FILE); + file << DATA; + file.close(); + } + + auto methodHandler = [&](const PeerID, std::shared_ptr&, MethodResult::Pointer methodResult) { + int fd = ::open(TEST_FILE.c_str(), O_RDONLY); + auto returnData = std::make_shared(fd); + methodResult->set(returnData); + }; + + Service s(F::getPoll(), SOCKET_PATH); + s.setMethodHandler(1, methodHandler); + + Client c(F::getPoll(), SOCKET_PATH); + connect(s, c); + + std::shared_ptr fdData; + std::shared_ptr sentData(new EmptyData()); + fdData = c.callSync(1, sentData, TIMEOUT); + + // Use the file descriptor + char buffer[sizeof(DATA)]; + BOOST_REQUIRE(::read(fdData->fd.value, buffer, sizeof(buffer))>0); + BOOST_REQUIRE(strncmp(DATA, buffer, strlen(DATA))==0); + ::close(fdData->fd.value); +} + // MULTI_FIXTURE_TEST_CASE(ConnectionLimit, F, ThreadedFixture, GlibFixture) // { // unsigned oldLimit = ipc::getMaxFDNumber(); -- 2.7.4 From 314f5334d5fa3cf8d7dfe6207fc5e7aa10acccdc Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 29 May 2015 14:44:12 +0200 Subject: [PATCH 08/16] Various changes relating to build on Fedora Linux. [Bug/Feature] Support different versions of json-c. Unify installation paths. Fix compiler warnings. Support different platform type in RPM spec file. Small changes in deamon and service configuration. [Cause] N/A [Solution] N/A [Verification] Build, run tests, run server on Tizen and Fedora. Select platform type with --define 'platform_type FEDORA or TIZEN' Change-Id: I6ef85e9605d2069701ee68dd8e8946f0346387f5 --- CMakeLists.txt | 18 ++++---- client/CMakeLists.txt | 2 +- libs/config/CMakeLists.txt | 6 ++- libs/config/from-json-visitor.hpp | 5 +++ libs/config/from-kvjson-visitor.hpp | 5 +++ libs/config/to-json-visitor.hpp | 9 ++++ libs/logger/ccolor.cpp | 2 +- packaging/vasum.spec | 48 ++++++++++++++++++---- server/CMakeLists.txt | 2 +- server/configs/daemon.conf.in | 6 +-- server/configs/systemd/vasum.service.in | 1 - server/configs/templates/tizen-common-wayland.sh | 2 + .../network_tests/network_common.py | 2 +- tests/unit_tests/CMakeLists.txt | 2 +- tests/unit_tests/configs/CMakeLists.txt | 5 ++- ...t-test.service => vasum-socket-test.service.in} | 2 +- wrapper/CMakeLists.txt | 2 +- 17 files changed, 88 insertions(+), 31 deletions(-) rename tests/unit_tests/configs/systemd/{vasum-socket-test.service => vasum-socket-test.service.in} (72%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d42f496..e865117 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,11 @@ ADD_DEFINITIONS(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}") ADD_DEFINITIONS(-DUSE_EXEC) ADD_DEFINITIONS(-D__STDC_LIMIT_MACROS) +PKG_SEARCH_MODULE(JSON_C REQUIRED json json-c) +IF(JSON_C_VERSION GREATER 0.11) + ADD_DEFINITIONS(-DJSON_C_VERSION_NEW) +ENDIF(JSON_C_VERSION GREATER 0.11) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Warn about documentation problems ADD_DEFINITIONS("-Wdocumentation") @@ -151,32 +156,29 @@ SET(TESTS_FOLDER ${PROJECT_SOURCE_DIR}/tests) SET(CLI_FOLDER ${PROJECT_SOURCE_DIR}/cli) SET(WRAPPER_FOLDER ${PROJECT_SOURCE_DIR}/wrapper) + IF(NOT DEFINED SYSCONF_INSTALL_DIR) SET(SYSCONF_INSTALL_DIR "/etc") ENDIF(NOT DEFINED SYSCONF_INSTALL_DIR) IF(NOT DEFINED LIB_INSTALL_DIR) - SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") + SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib") ENDIF(NOT DEFINED LIB_INSTALL_DIR) IF(NOT DEFINED INCLUDE_INSTALL_DIR) - SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") ENDIF(NOT DEFINED INCLUDE_INSTALL_DIR) IF(NOT DEFINED SCRIPT_INSTALL_DIR) - SET(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_FULL_SBINDIR}") + SET(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_SBINDIR}") ENDIF(NOT DEFINED SCRIPT_INSTALL_DIR) -IF(NOT DEFINED SHARE_INSTALL_PREFIX) - SET(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_FULL_DATAROOTDIR}") -ENDIF(NOT DEFINED SHARE_INSTALL_PREFIX) - IF(NOT DEFINED SYSTEMD_UNIT_DIR) SET(SYSTEMD_UNIT_DIR "${LIB_INSTALL_DIR}/systemd/system") ENDIF(NOT DEFINED SYSTEMD_UNIT_DIR) IF(NOT DEFINED DATA_DIR) - SET(DATA_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}") + SET(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share") ENDIF(NOT DEFINED DATA_DIR) SET(VSM_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/vasum) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c9f4c17..3fa44fd 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -62,7 +62,7 @@ INSTALL(FILES ${CMAKE_BINARY_DIR}/${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) INSTALL(TARGETS ${PROJECT_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR} + DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) INSTALL(FILES vasum-client.h diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index 87c2af1..fcc5e23 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -38,9 +38,11 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES ## Link libraries ############################################################## PKG_CHECK_MODULES(CONFIG_DEPS REQUIRED sqlite3 glib-2.0) +PKG_SEARCH_MODULE(JSON_C json json-c) + INCLUDE_DIRECTORIES(${LIBS_FOLDER}) -INCLUDE_DIRECTORIES(SYSTEM ${CONFIG_DEPS_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${CONFIG_DEPS_LIBRARIES}) +INCLUDE_DIRECTORIES(SYSTEM ${CONFIG_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${CONFIG_DEPS_LIBRARIES} ${JSON_C_LIBRARIES}) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/config/from-json-visitor.hpp b/libs/config/from-json-visitor.hpp index 2934adf..8831ef6 100644 --- a/libs/config/from-json-visitor.hpp +++ b/libs/config/from-json-visitor.hpp @@ -28,7 +28,12 @@ #include "config/is-visitable.hpp" #include "config/exception.hpp" +#ifdef JSON_C_VERSION_NEW +#include +#else //JSON_C_VERSION_NEW #include +#endif //JSON_C_VERSION_NEW + #include #include diff --git a/libs/config/from-kvjson-visitor.hpp b/libs/config/from-kvjson-visitor.hpp index 35e1bf7..f9c11ef 100644 --- a/libs/config/from-kvjson-visitor.hpp +++ b/libs/config/from-kvjson-visitor.hpp @@ -28,7 +28,12 @@ #include "config/from-kvstore-visitor.hpp" #include "config/is-union.hpp" + +#ifdef JSON_C_VERSION_NEW +#include +#else //JSON_C_VERSION_NEW #include +#endif //JSON_C_VERSION_NEW namespace config { diff --git a/libs/config/to-json-visitor.hpp b/libs/config/to-json-visitor.hpp index f524900..1b68438 100644 --- a/libs/config/to-json-visitor.hpp +++ b/libs/config/to-json-visitor.hpp @@ -28,7 +28,12 @@ #include "config/is-visitable.hpp" #include "config/exception.hpp" +#ifdef JSON_C_VERSION_NEW +#include +#else //JSON_C_VERSION_NEW #include +#endif //JSON_C_VERSION_NEW + #include #include @@ -108,7 +113,11 @@ private: static json_object* toJsonObject(double value) { +#ifdef JSON_C_VERSION_NEW + return json_object_new_double_s(value, std::to_string(value).c_str()); +#else //JSON_C_VERSION_NEW return json_object_new_double(value); +#endif //JSON_C_VERSION_NEW } static json_object* toJsonObject(const std::string& value) diff --git a/libs/logger/ccolor.cpp b/libs/logger/ccolor.cpp index 7424044..9cc652d 100644 --- a/libs/logger/ccolor.cpp +++ b/libs/logger/ccolor.cpp @@ -34,7 +34,7 @@ std::string getConsoleEscapeSequence(Attributes attr, Color color) char command[10]; // Command is the control command to the terminal - snprintf(command, sizeof(command), "%c[%d;%dm", 0x1B, attr, color); + snprintf(command, sizeof(command), "%c[%u;%um", 0x1B, (unsigned int)attr, (unsigned int)color); return std::string(command); } diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 8f10a1c..bd7346c 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -8,6 +8,8 @@ %define disk_group disk # The group that has write access to /dev/tty* devices. %define tty_group tty +# Default platform is Tizen, setup Fedora with --define 'platform_type FEDORA' +%{!?platform_type:%define platform_type "TIZEN"} Name: vasum Epoch: 1 @@ -19,13 +21,16 @@ Group: Security/Other Summary: Daemon for managing zones BuildRequires: cmake BuildRequires: boost-devel -BuildRequires: libjson-devel >= 0.10 -BuildRequires: lxc-devel BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(sqlite3) -Requires(post): libcap-tools +BuildRequires: lxc-devel +Requires: lxc +%if %{platform_type} == "TIZEN" Requires: iproute2 -Requires: libjson >= 0.10 +Requires(post): libcap-tools +%else +Requires: iproute +Requires(post): libcap +%endif Obsoletes: vasum-daemon < 1:0 %description @@ -34,11 +39,12 @@ between them. A process from inside a zone can request a switch of context (display, input devices) to the other zone. %files +%if %{platform_type} == "TIZEN" %manifest packaging/vasum.manifest +%endif %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/vasum-server %dir /etc/vasum -%dir /etc/vasum/zones %dir /etc/vasum/templates %config /etc/vasum/daemon.conf %attr(755,root,root) /etc/vasum/templates/*.sh @@ -47,7 +53,7 @@ between them. A process from inside a zone can request a switch of context %{_unitdir}/vasum.socket %{_unitdir}/multi-user.target.wants/vasum.service %config /etc/dbus-1/system.d/org.tizen.vasum.host.conf -%dir %{_datadir}/.zones +%dir %{_datadir}/zones %prep %setup -q @@ -77,7 +83,7 @@ make -k %{?jobs:-j%jobs} %make_install 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 +mkdir -p %{buildroot}/%{_datadir}/zones %clean rm -rf %{buildroot} @@ -127,7 +133,9 @@ Library interface to the vasum daemon %postun -n vasum-client -p /sbin/ldconfig %files client +%if %{platform_type} == "TIZEN" %manifest packaging/libvasum-client.manifest +%endif %defattr(644,root,root,755) %attr(755,root,root) %{_libdir}/libvasum-client.so.%{version} %{_libdir}/libvasum-client.so.0 @@ -146,7 +154,9 @@ Requires: vasum-client = %{epoch}:%{version}-%{release} Development package including the header files for the client library %files devel +%if %{platform_type} == "TIZEN" %manifest packaging/vasum.manifest +%endif %defattr(644,root,root,755) %{_libdir}/libvasum-client.so %{_libdir}/libvasum.so @@ -164,7 +174,9 @@ Group: Security/Other Zones support installed inside every zone. %files zone-support +%if %{platform_type} == "TIZEN" %manifest packaging/vasum-zone-support.manifest +%endif %defattr(644,root,root,755) %config /etc/dbus-1/system.d/org.tizen.vasum.zone.conf @@ -179,7 +191,9 @@ Requires: vasum-zone-support = %{epoch}:%{version}-%{release} Daemon running inside every zone. %files zone-daemon +%if %{platform_type} == "TIZEN" %manifest packaging/vasum-zone-daemon.manifest +%endif %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/vasum-zone-daemon %config /etc/dbus-1/system.d/org.tizen.vasum.zone.daemon.conf @@ -217,7 +231,9 @@ Group: Development/Libraries Requires: vasum = %{epoch}:%{version}-%{release} Requires: vasum-client = %{epoch}:%{version}-%{release} Requires: python +%if %{platform_type} == "TIZEN" Requires: python-xml +%endif Requires: boost-test %description tests @@ -236,7 +252,9 @@ systemctl disable vasum-socket-test.socket systemctl daemon-reload %files tests +%if %{platform_type} == "TIZEN" %manifest packaging/vasum-server-tests.manifest +%endif %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/vasum-server-unit-tests %attr(755,root,root) %{_bindir}/vasum-socket-test @@ -327,6 +345,14 @@ The package provides libSimpleDbus development tools and libs. %package -n libConfig Summary: Config library Group: Security/Other +BuildRequires: pkgconfig(sqlite3) +%if %{platform_type} == "TIZEN" +BuildRequires: libjson-devel >= 0.10 +Requires: libjson >= 0.10 +%else +BuildRequires: json-c-devel +Requires: json-c +%endif Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig @@ -348,7 +374,11 @@ Group: Development/Libraries Requires: libConfig = %{epoch}:%{version}-%{release} Requires: boost-devel Requires: pkgconfig(libLogger) -Requires: libjson-devel +%if %{platform_type} == "TIZEN" +Requires: libjson-devel >= 0.10 +%else +Requires: json-c-devel +%endif %description -n libConfig-devel The package provides libConfig development tools and libs. diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 9a1985c..92672c1 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -30,7 +30,7 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) -PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0) +PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc glib-2.0 gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index b94eb29..f3dd9fd 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -1,13 +1,13 @@ { - "dbPath" : "/usr/dbspace/vasum.db", + "dbPath" : "/etc/vasum/vasum.db", "zoneIds" : [], - "zonesPath" : "${DATA_DIR}/.zones", + "zonesPath" : "${DATA_DIR}/zones", "zoneImagePath" : "", "zoneTemplateDir" : "/etc/vasum/templates/", "runMountPointPrefix" : "/var/run/zones", "defaultId" : "", "availableVTs" : [3, 4, 5, 6], - "inputConfig" : {"enabled" : true, + "inputConfig" : {"enabled" : false, "device" : "gpio_keys.6", "code" : 116, "numberOfEvents" : 2, diff --git a/server/configs/systemd/vasum.service.in b/server/configs/systemd/vasum.service.in index 29ebbc8..1b6284f 100644 --- a/server/configs/systemd/vasum.service.in +++ b/server/configs/systemd/vasum.service.in @@ -1,6 +1,5 @@ [Unit] Description=Vasum Server -ConditionVirtualization=no [Service] Type=simple diff --git a/server/configs/templates/tizen-common-wayland.sh b/server/configs/templates/tizen-common-wayland.sh index 5c57aff..30b90cd 100755 --- a/server/configs/templates/tizen-common-wayland.sh +++ b/server/configs/templates/tizen-common-wayland.sh @@ -122,6 +122,8 @@ ${path}/systemd/user /bin/ln -s /dev/null ${path}/systemd/system/systemd-udevd.service /bin/ln -s /dev/null ${path}/systemd/system/systemd-udevd-kernel.socket /bin/ln -s /dev/null ${path}/systemd/system/systemd-udevd-control.socket +/bin/ln -s /dev/null ${path}/systemd/system/vasum.service +/bin/ln -s /dev/null ${path}/systemd/system/vasum.socket /bin/ln -s /dev/null ${path}/systemd/system/vconf-setup.service /bin/ln -s /usr/lib/systemd/system/tlm.service ${path}/systemd/system/multi-user.target.wants/tlm.service /bin/ln -s /dev/null ${path}/systemd/user/media-server-user.service diff --git a/tests/integration_tests/network_tests/network_common.py b/tests/integration_tests/network_tests/network_common.py index acb120c..98e85b5 100755 --- a/tests/integration_tests/network_tests/network_common.py +++ b/tests/integration_tests/network_tests/network_common.py @@ -31,7 +31,7 @@ TEST_URL_INTERNET=["www.samsung.com", "www.google.com", "www.oracle.com"] #TODO read path from config (daemon.conf) # Path to test zone -TEST_ZONE_PATH="/usr/share/.zones" +TEST_ZONE_PATH="/usr/share/zones" # Device Ethernet device ETHERNET_DEVICE="usb0" diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 484e810..46a9a3b 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -47,7 +47,7 @@ ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS} ${clie ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) -PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0) +PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER} ${LIBS_FOLDER} ${SOCKET_TEST_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) diff --git a/tests/unit_tests/configs/CMakeLists.txt b/tests/unit_tests/configs/CMakeLists.txt index a18914e..6bffac4 100644 --- a/tests/unit_tests/configs/CMakeLists.txt +++ b/tests/unit_tests/configs/CMakeLists.txt @@ -34,6 +34,9 @@ CONFIGURE_FILE(templates/console-ipc.conf.in ${CMAKE_BINARY_DIR}/templates/console-ipc.conf @ONLY) FILE(GLOB ut_zone_templates_CONF_GEN ${CMAKE_BINARY_DIR}/templates/*.conf) +CONFIGURE_FILE(systemd/vasum-socket-test.service.in + ${CMAKE_BINARY_DIR}/systemd/vasum-socket-test.service) + ## Install ##################################################################### INSTALL(FILES ${ut_zone_CONF} @@ -58,7 +61,7 @@ INSTALL(FILES utils/file.txt DESTINATION ${VSM_TEST_CONFIG_INSTALL_DIR}/utils) INSTALL(FILES systemd/vasum-socket-test.socket - systemd/vasum-socket-test.service + ${CMAKE_BINARY_DIR}/systemd/vasum-socket-test.service DESTINATION ${SYSTEMD_UNIT_DIR}) INSTALL(FILES dbus-1/system.d/org.tizen.vasum.tests.conf diff --git a/tests/unit_tests/configs/systemd/vasum-socket-test.service b/tests/unit_tests/configs/systemd/vasum-socket-test.service.in similarity index 72% rename from tests/unit_tests/configs/systemd/vasum-socket-test.service rename to tests/unit_tests/configs/systemd/vasum-socket-test.service.in index 23c6d3a..b5da48b 100644 --- a/tests/unit_tests/configs/systemd/vasum-socket-test.service +++ b/tests/unit_tests/configs/systemd/vasum-socket-test.service.in @@ -3,7 +3,7 @@ Description=Vasum Socket tests mini-service [Service] Type=simple -ExecStart=/usr/bin/vasum-socket-test +ExecStart=${CMAKE_INSTALL_PREFIX}/bin/vasum-socket-test Sockets=vasum-socket-test.socket StartLimitInterval=0 StartLimitBurst=0 diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt index a8aa173..23fdba6 100644 --- a/wrapper/CMakeLists.txt +++ b/wrapper/CMakeLists.txt @@ -70,7 +70,7 @@ INSTALL(FILES ${CMAKE_BINARY_DIR}/${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) INSTALL(TARGETS ${PROJECT_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR} + DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) INSTALL(FILES vasum.h vasum_list.h -- 2.7.4 From 48f17bbffc27fe5cc6d9491bdccdb6fcd5c42777 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 26 May 2015 08:52:19 +0200 Subject: [PATCH 09/16] Remove useless callback layer from Host*Connection [Bug] Host*Connection classes had redundant callback layer. [Cause] N/A [Solution] Make Host*Connection objects aware of ZonesManager. Remove unneeded callbacks. [Verification] For both with and without Dbus: * Build * Run tests * Make sure, that vasum-cli works Change-Id: I8fd76d279731efdf201e797f2ef7600aed355aaa --- server/host-dbus-connection.cpp | 324 +++++++--------------------------- server/host-dbus-connection.hpp | 266 +--------------------------- server/host-ipc-connection.cpp | 92 +++++++++- server/host-ipc-connection.hpp | 13 +- server/zones-manager.cpp | 96 +--------- server/zones-manager.hpp | 117 ++++++------ tests/unit_tests/client/ut-client.cpp | 1 + 7 files changed, 231 insertions(+), 678 deletions(-) diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index ad0ba0d..7714b65 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -32,6 +32,7 @@ #include "logger/logger.hpp" #include "config/manager.hpp" +#include "zones-manager.hpp" namespace vasum { @@ -41,13 +42,15 @@ namespace { // Can happen if glib loop is busy or not present. // TODO: this should be in host's configuration file const unsigned int NAME_ACQUIRED_TIMEOUT = 5 * 1000; +const std::string EMPTY_CALLER = ""; } // namespace -HostDbusConnection::HostDbusConnection() +HostDbusConnection::HostDbusConnection(ZonesManager* zonesManagerPtr) : mNameAcquired(false) , mNameLost(false) + , mZonesManagerPtr(zonesManagerPtr) { LOGT("Connecting to host system DBUS"); mDbusConnection = dbus::DbusConnection::createSystem(); @@ -117,151 +120,6 @@ void HostDbusConnection::setProxyCallCallback(const ProxyCallCallback& callback) mProxyCallCallback = callback; } -void HostDbusConnection::setGetZoneConnectionsCallback(const GetZoneConnectionsCallback& callback) -{ - mGetZoneConnectionsCallback = callback; -} - -void HostDbusConnection::setGetZoneIdsCallback(const GetZoneIdsCallback& callback) -{ - mGetZoneIdsCallback = callback; -} - -void HostDbusConnection::setGetActiveZoneIdCallback(const GetActiveZoneIdCallback& callback) -{ - mGetActiveZoneIdCallback = callback; -} - -void HostDbusConnection::setGetZoneInfoCallback(const GetZoneInfoCallback& callback) -{ - mGetZoneInfoCallback = callback; -} - -void HostDbusConnection::setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback) -{ - mSetNetdevAttrsCallback = callback; -} - -void HostDbusConnection::setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback) -{ - mGetNetdevAttrsCallback = callback; -} - -void HostDbusConnection::setGetNetdevListCallback(const GetNetdevListCallback& callback) -{ - mGetNetdevListCallback = callback; -} - -void HostDbusConnection::setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback) -{ - mCreateNetdevVethCallback = callback; -} - -void HostDbusConnection::setCreateNetdevMacvlanCallback(const CreateNetdevMacvlanCallback& callback) -{ - mCreateNetdevMacvlanCallback = callback; -} - -void HostDbusConnection::setCreateNetdevPhysCallback(const CreateNetdevPhysCallback& callback) -{ - mCreateNetdevPhysCallback = callback; -} - -void HostDbusConnection::setDestroyNetdevCallback(const DestroyNetdevCallback& callback) -{ - mDestroyNetdevCallback = callback; -} - -void HostDbusConnection::setDeleteNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback) -{ - mDeleteNetdevIpAddressCallback = callback; -} - -void HostDbusConnection::setDeclareFileCallback(const DeclareFileCallback& callback) -{ - mDeclareFileCallback = callback; -} - -void HostDbusConnection::setDeclareMountCallback(const DeclareMountCallback& callback) -{ - mDeclareMountCallback = callback; -} - -void HostDbusConnection::setDeclareLinkCallback(const DeclareLinkCallback& callback) -{ - mDeclareLinkCallback = callback; -} - -void HostDbusConnection::setGetDeclarationsCallback(const GetDeclarationsCallback& callback) -{ - mGetDeclarationsCallback = callback; -} - -void HostDbusConnection::setRemoveDeclarationCallback(const RemoveDeclarationCallback& callback) -{ - mRemoveDeclarationCallback = callback; -} - -void HostDbusConnection::setSetActiveZoneCallback(const SetActiveZoneCallback& callback) -{ - mSetActiveZoneCallback = callback; -} - -void HostDbusConnection::setCreateZoneCallback(const CreateZoneCallback& callback) -{ - mCreateZoneCallback = callback; -} - -void HostDbusConnection::setDestroyZoneCallback(const DestroyZoneCallback& callback) -{ - mDestroyZoneCallback = callback; -} - -void HostDbusConnection::setShutdownZoneCallback(const ShutdownZoneCallback& callback) -{ - mShutdownZoneCallback = callback; -} - -void HostDbusConnection::setStartZoneCallback(const StartZoneCallback& callback) -{ - mStartZoneCallback = callback; -} - -void HostDbusConnection::setLockZoneCallback(const LockZoneCallback& callback) -{ - mLockZoneCallback = callback; -} - -void HostDbusConnection::setUnlockZoneCallback(const UnlockZoneCallback& callback) -{ - mUnlockZoneCallback = callback; -} - -void HostDbusConnection::setGrantDeviceCallback(const GrantDeviceCallback& callback) -{ - mGrantDeviceCallback = callback; -} - -void HostDbusConnection::setRevokeDeviceCallback(const RevokeDeviceCallback& callback) -{ - mRevokeDeviceCallback = callback; -} - -void HostDbusConnection::setNotifyActiveZoneCallback(const NotifyActiveZoneCallback& callback) -{ - mNotifyActiveZoneCallback = callback; -} - -void HostDbusConnection::setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback) -{ - mSwitchToDefaultCallback = callback; -} - -void HostDbusConnection::setFileMoveCallback(const FileMoveCallback& callback) -{ - mFileMoveCallback = callback; -} - void HostDbusConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, @@ -276,10 +134,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId zoneId; config::loadFromGVariant(parameters, zoneId); - if (mSetActiveZoneCallback) { - auto rb = std::make_shared>(result); - mSetActiveZoneCallback(zoneId, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleSetActiveZoneCall(zoneId, rb); return; } @@ -313,18 +169,14 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, } if (methodName == api::dbus::METHOD_GET_ZONE_ID_LIST) { - if (mGetZoneIdsCallback) { - auto rb = std::make_shared>(result); - mGetZoneIdsCallback(rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetZoneIdsCall(rb); return; } if (methodName == api::dbus::METHOD_GET_ACTIVE_ZONE_ID) { - if (mGetActiveZoneIdCallback) { - auto rb = std::make_shared>(result); - mGetActiveZoneIdCallback(rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetActiveZoneIdCall(rb); return; } @@ -332,10 +184,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId zoneId; config::loadFromGVariant(parameters, zoneId); - if (mGetZoneInfoCallback) { - auto rb = std::make_shared>(result); - mGetZoneInfoCallback(zoneId, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetZoneInfoCall(zoneId, rb); return; } @@ -343,10 +193,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::SetNetDevAttrsIn data; config::loadFromGVariant(parameters, data); - if (mSetNetdevAttrsCallback) { - auto rb = std::make_shared>(result); - mSetNetdevAttrsCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleSetNetdevAttrsCall(data, rb); return; } @@ -354,10 +202,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::GetNetDevAttrsIn data; config::loadFromGVariant(parameters, data); - if (mGetNetdevAttrsCallback) { - auto rb = std::make_shared>(result); - mGetNetdevAttrsCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetNetdevAttrsCall(data, rb); return; } @@ -365,10 +211,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mGetNetdevListCallback) { - auto rb = std::make_shared>(result); - mGetNetdevListCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetNetdevListCall(data, rb); return; } @@ -376,10 +220,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::CreateNetDevVethIn data; config::loadFromGVariant(parameters, data); - if (mCreateNetdevVethCallback) { - auto rb = std::make_shared>(result); - mCreateNetdevVethCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCreateNetdevVethCall(data, rb); return; } @@ -387,49 +229,44 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::CreateNetDevMacvlanIn data; config::loadFromGVariant(parameters, data); - if (mCreateNetdevMacvlanCallback) { - auto rb = std::make_shared>(result); - mCreateNetdevMacvlanCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCreateNetdevMacvlanCall(data, rb); + return; } if (methodName == api::dbus::METHOD_CREATE_NETDEV_PHYS) { api::CreateNetDevPhysIn data; config::loadFromGVariant(parameters, data); - if (mCreateNetdevPhysCallback) { - auto rb = std::make_shared>(result); - mCreateNetdevPhysCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCreateNetdevPhysCall(data, rb); + return; } if (methodName == api::dbus::METHOD_DESTROY_NETDEV) { api::DestroyNetDevIn data; config::loadFromGVariant(parameters, data); - if (mDestroyNetdevCallback) { - auto rb = std::make_shared>(result); - mDestroyNetdevCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDestroyNetdevCall(data, rb); + return; } if (methodName == api::dbus::METHOD_DELETE_NETDEV_IP_ADDRESS) { api::DeleteNetdevIpAddressIn data; config::loadFromGVariant(parameters, data); - if (mDeleteNetdevIpAddressCallback) { - auto rb = std::make_shared>(result); - mDeleteNetdevIpAddressCallback(data, rb); - } + + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDeleteNetdevIpAddressCall(data, rb); + return; } if (methodName == api::dbus::METHOD_DECLARE_FILE) { api::DeclareFileIn data; config::loadFromGVariant(parameters, data); - if (mDeclareFileCallback) { - auto rb = std::make_shared>(result); - mDeclareFileCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDeclareFileCall(data, rb); return; } @@ -437,10 +274,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::DeclareMountIn data; config::loadFromGVariant(parameters, data); - if (mDeclareMountCallback) { - auto rb = std::make_shared>(result); - mDeclareMountCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDeclareMountCall(data, rb); return; } @@ -448,10 +283,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::DeclareLinkIn data; config::loadFromGVariant(parameters, data); - if (mDeclareLinkCallback) { - auto rb = std::make_shared>(result); - mDeclareLinkCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDeclareLinkCall(data, rb); return; } @@ -459,10 +292,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mGetDeclarationsCallback) { - auto rb = std::make_shared>(result); - mGetDeclarationsCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGetDeclarationsCall(data, rb); return; } @@ -470,10 +301,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::RemoveDeclarationIn data; config::loadFromGVariant(parameters, data); - if (mRemoveDeclarationCallback) { - auto rb = std::make_shared>(result); - mRemoveDeclarationCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleRemoveDeclarationCall(data, rb); return; } @@ -481,10 +310,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::CreateZoneIn data; config::loadFromGVariant(parameters, data); - if (mCreateZoneCallback) { - auto rb = std::make_shared>(result); - mCreateZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCreateZoneCall(data, rb); return; } @@ -492,10 +319,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mDestroyZoneCallback) { - auto rb = std::make_shared>(result); - mDestroyZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleDestroyZoneCall(data, rb); return; } @@ -503,30 +328,25 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mShutdownZoneCallback) { - auto rb = std::make_shared>(result); - mShutdownZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleShutdownZoneCall(data, rb); + return; } if (methodName == api::dbus::METHOD_START_ZONE) { api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mStartZoneCallback) { - auto rb = std::make_shared>(result); - mStartZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleStartZoneCall(data, rb); } if (methodName == api::dbus::METHOD_LOCK_ZONE) { api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mLockZoneCallback) { - auto rb = std::make_shared>(result); - mLockZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleLockZoneCall(data, rb); return; } @@ -534,10 +354,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::ZoneId data; config::loadFromGVariant(parameters, data); - if (mUnlockZoneCallback) { - auto rb = std::make_shared>(result); - mUnlockZoneCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleUnlockZoneCall(data, rb); return; } @@ -545,10 +363,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::GrantDeviceIn data; config::loadFromGVariant(parameters, data); - if (mGrantDeviceCallback) { - auto rb = std::make_shared>(result); - mGrantDeviceCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleGrantDeviceCall(data, rb); return; } @@ -556,10 +372,8 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::RevokeDeviceIn data; config::loadFromGVariant(parameters, data); - if (mRevokeDeviceCallback) { - auto rb = std::make_shared>(result); - mRevokeDeviceCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleRevokeDeviceCall(data, rb); return; } @@ -567,20 +381,18 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, api::NotifActiveZoneIn data; config::loadFromGVariant(parameters, data); - if (mNotifyActiveZoneCallback) { - auto rb = std::make_shared>(result); - mNotifyActiveZoneCallback(data, rb); - } + 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); - if (mFileMoveCallback) { - auto rb = std::make_shared>(result); - mFileMoveCallback(data, rb); - } + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleFileMoveCall(EMPTY_CALLER, data, rb); + return; } } @@ -595,9 +407,7 @@ void HostDbusConnection::onSignalCall(const std::string& /* senderBusName */, } if (signalName == api::dbus::SIGNAL_SWITCH_TO_DEFAULT) { - if (mSwitchToDefaultCallback) { - mSwitchToDefaultCallback(); - } + mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER); } } diff --git a/server/host-dbus-connection.hpp b/server/host-dbus-connection.hpp index cdd8dda..23bb9d9 100644 --- a/server/host-dbus-connection.hpp +++ b/server/host-dbus-connection.hpp @@ -39,11 +39,12 @@ namespace vasum { +class ZonesManager; class HostDbusConnection { public: - HostDbusConnection(); + HostDbusConnection(ZonesManager* zm); ~HostDbusConnection(); // ------------- API -------------- @@ -56,89 +57,6 @@ public: GVariant* parameters, dbus::MethodResultBuilder::Pointer result )> ProxyCallCallback; - typedef std::function GetZoneConnectionsCallback; - typedef std::function GetZoneIdsCallback; - typedef std::function GetActiveZoneIdCallback; - typedef std::function GetZoneInfoCallback; - typedef std::function SetNetdevAttrsCallback; - typedef std::function GetNetdevAttrsCallback; - typedef std::function GetNetdevListCallback; - typedef std::function CreateNetdevVethCallback; - typedef std::function CreateNetdevMacvlanCallback; - typedef std::function CreateNetdevPhysCallback; - typedef std::function DeleteNetdevIpAddressCallback; - typedef std::function DestroyNetdevCallback; - typedef std::function DeclareFileCallback; - typedef std::function DeclareMountCallback; - typedef std::function DeclareLinkCallback; - typedef std::function GetDeclarationsCallback; - typedef std::function RemoveDeclarationCallback; - typedef std::function SetActiveZoneCallback; - typedef std::function CreateZoneCallback; - typedef std::function DestroyZoneCallback; - typedef std::function ShutdownZoneCallback; - typedef std::function StartZoneCallback; - typedef std::function LockZoneCallback; - typedef std::function UnlockZoneCallback; - typedef std::function GrantDeviceCallback; - typedef std::function RevokeDeviceCallback; - typedef std::function NotifyActiveZoneCallback; - typedef std::function FileMoveCallback; - typedef std::function SwitchToDefaultCallback; - /** * Register proxy call callback @@ -146,156 +64,6 @@ public: void setProxyCallCallback(const ProxyCallCallback& callback); /** - * Register get zone connections callback - */ - void setGetZoneConnectionsCallback(const GetZoneConnectionsCallback& callback); - - /** - * Send signal describing dbus address state change - */ - void signalZoneConnectionState(const api::ConnectionState& state); - - /** - * Register a callback called to get a list of zone ids - */ - void setGetZoneIdsCallback(const GetZoneIdsCallback& callback); - - /** - * Register a callback called to get the active zone id - */ - void setGetActiveZoneIdCallback(const GetActiveZoneIdCallback& callback); - - /** - * Register a callback called to get the zone informations - */ - void setGetZoneInfoCallback(const GetZoneInfoCallback& callback); - - /** - * Register a callback called to set network device attributes - */ - void setSetNetdevAttrsCallback(const SetNetdevAttrsCallback& callback); - - /** - * Register a callback called to get network device attributes - */ - void setGetNetdevAttrsCallback(const GetNetdevAttrsCallback& callback); - - /** - * Register a callback called to get network device list - */ - void setGetNetdevListCallback(const GetNetdevListCallback& callback); - - /** - * Register a callback called to create veth - */ - void setCreateNetdevVethCallback(const CreateNetdevVethCallback& callback); - - /** - * Register a callback called to create macvlan - */ - void setCreateNetdevMacvlanCallback(const CreateNetdevMacvlanCallback& callback); - - /** - * Register a callback called to create/move phys - */ - void setCreateNetdevPhysCallback(const CreateNetdevPhysCallback& callback); - - /** - * Register a callback called to destroy netdev - */ - void setDestroyNetdevCallback(const DestroyNetdevCallback& callback); - - /** - * Register a callback called to remove ip address from netdev - */ - void setDeleteNetdevIpAddressCallback(const DeleteNetdevIpAddressCallback& callback); - - /** - * Register a callback called to declare file - */ - void setDeclareFileCallback(const DeclareFileCallback& callback); - - /** - * Register a callback called to declare mount point - */ - void setDeclareMountCallback(const DeclareMountCallback& callback); - - /** - * Register a callback called to declare link - */ - void setDeclareLinkCallback(const DeclareLinkCallback& callback); - - /** - * Register a callback called to list declarations - */ - void setGetDeclarationsCallback(const GetDeclarationsCallback& callback); - - /** - * Register a callback called to remove declarartion - */ - void setRemoveDeclarationCallback(const RemoveDeclarationCallback& callback); - - /** - * Register a callback called to set the active zone - */ - void setSetActiveZoneCallback(const SetActiveZoneCallback& callback); - - /** - * Register a callback called to create new zone - */ - void setCreateZoneCallback(const CreateZoneCallback& callback); - - /** - * Register a callback called to destroy zone - */ - void setDestroyZoneCallback(const DestroyZoneCallback& callback); - - /** - * Register a callback called to shutdown zone - */ - void setShutdownZoneCallback(const ShutdownZoneCallback& callback); - - /** - * Register a callback called to start zone - */ - void setStartZoneCallback(const StartZoneCallback& callback); - - /** - * Register a callback called to lock zone - */ - void setLockZoneCallback(const LockZoneCallback& callback); - - /** - * Register a callback called to unlock zone - */ - void setUnlockZoneCallback(const UnlockZoneCallback& callback); - - /** - * Register a callback called to grant device - */ - void setGrantDeviceCallback(const GrantDeviceCallback& callback); - - /** - * Register a callback called to revoke device - */ - void setRevokeDeviceCallback(const RevokeDeviceCallback& callback); - - /** - * Register notification request callback - */ - void setNotifyActiveZoneCallback(const NotifyActiveZoneCallback& callback); - - /** - * Register switch to default request callback - */ - void setSwitchToDefaultCallback(const SwitchToDefaultCallback& callback); - - /* - * Register file move request callback - */ - void setFileMoveCallback(const FileMoveCallback& callback); - - /** * Send notification signal to this zone */ void sendNotification(const api::Notification& notify); @@ -318,35 +86,7 @@ private: bool mNameLost; dbus::DbusConnection::SubscriptionId mSubscriptionId; ProxyCallCallback mProxyCallCallback; - GetZoneConnectionsCallback mGetZoneConnectionsCallback; - GetZoneIdsCallback mGetZoneIdsCallback; - GetActiveZoneIdCallback mGetActiveZoneIdCallback; - GetZoneInfoCallback mGetZoneInfoCallback; - SetNetdevAttrsCallback mSetNetdevAttrsCallback; - GetNetdevAttrsCallback mGetNetdevAttrsCallback; - GetNetdevListCallback mGetNetdevListCallback; - CreateNetdevVethCallback mCreateNetdevVethCallback; - CreateNetdevMacvlanCallback mCreateNetdevMacvlanCallback; - CreateNetdevPhysCallback mCreateNetdevPhysCallback; - DestroyNetdevCallback mDestroyNetdevCallback; - DeleteNetdevIpAddressCallback mDeleteNetdevIpAddressCallback; - DeclareFileCallback mDeclareFileCallback; - DeclareMountCallback mDeclareMountCallback; - DeclareLinkCallback mDeclareLinkCallback; - GetDeclarationsCallback mGetDeclarationsCallback; - RemoveDeclarationCallback mRemoveDeclarationCallback; - SetActiveZoneCallback mSetActiveZoneCallback; - CreateZoneCallback mCreateZoneCallback; - DestroyZoneCallback mDestroyZoneCallback; - ShutdownZoneCallback mShutdownZoneCallback; - StartZoneCallback mStartZoneCallback; - LockZoneCallback mLockZoneCallback; - UnlockZoneCallback mUnlockZoneCallback; - GrantDeviceCallback mGrantDeviceCallback; - RevokeDeviceCallback mRevokeDeviceCallback; - NotifyActiveZoneCallback mNotifyActiveZoneCallback; - SwitchToDefaultCallback mSwitchToDefaultCallback; - FileMoveCallback mFileMoveCallback; + ZonesManager* mZonesManagerPtr; void onNameAcquired(); void onNameLost(); diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index d6519e9..1a003d4 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -24,14 +24,19 @@ #include "config.hpp" +#include + #include "host-ipc-connection.hpp" #include "host-ipc-definitions.hpp" #include "exception.hpp" #include "logger/logger.hpp" +#include "zones-manager.hpp" + namespace vasum { -HostIPCConnection::HostIPCConnection() +HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) + : mZonesManagerPtr(zonesManagerPtr) { LOGT("Connecting to host IPC socket"); mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET)); @@ -39,6 +44,91 @@ HostIPCConnection::HostIPCConnection() LOGT("Starting IPC"); mService->start(); LOGD("Connected"); + + using namespace std::placeholders; + setGetZoneIdsCallback(std::bind(&ZonesManager::handleGetZoneIdsCall, + mZonesManagerPtr, _1)); + + setGetActiveZoneIdCallback(std::bind(&ZonesManager::handleGetActiveZoneIdCall, + mZonesManagerPtr, _1)); + + setGetZoneInfoCallback(std::bind(&ZonesManager::handleGetZoneInfoCall, + mZonesManagerPtr, _1, _2)); + + setSetNetdevAttrsCallback(std::bind(&ZonesManager::handleSetNetdevAttrsCall, + mZonesManagerPtr, _1, _2)); + + setGetNetdevAttrsCallback(std::bind(&ZonesManager::handleGetNetdevAttrsCall, + mZonesManagerPtr, _1, _2)); + + setGetNetdevListCallback(std::bind(&ZonesManager::handleGetNetdevListCall, + mZonesManagerPtr, _1, _2)); + + setCreateNetdevVethCallback(std::bind(&ZonesManager::handleCreateNetdevVethCall, + mZonesManagerPtr, _1, _2)); + + setCreateNetdevMacvlanCallback(std::bind(&ZonesManager::handleCreateNetdevMacvlanCall, + mZonesManagerPtr, _1, _2)); + + setCreateNetdevPhysCallback(std::bind(&ZonesManager::handleCreateNetdevPhysCall, + mZonesManagerPtr, _1, _2)); + + setDestroyNetdevCallback(std::bind(&ZonesManager::handleDestroyNetdevCall, + mZonesManagerPtr, _1, _2)); + + setDeleteNetdevIpAddressCallback(std::bind(&ZonesManager::handleDeleteNetdevIpAddressCall, + mZonesManagerPtr, _1, _2)); + + setDeclareFileCallback(std::bind(&ZonesManager::handleDeclareFileCall, + mZonesManagerPtr, _1, _2)); + + setDeclareMountCallback(std::bind(&ZonesManager::handleDeclareMountCall, + mZonesManagerPtr, _1, _2)); + + setDeclareLinkCallback(std::bind(&ZonesManager::handleDeclareLinkCall, + mZonesManagerPtr, _1, _2)); + + setGetDeclarationsCallback(std::bind(&ZonesManager::handleGetDeclarationsCall, + mZonesManagerPtr, _1, _2)); + + setRemoveDeclarationCallback(std::bind(&ZonesManager::handleRemoveDeclarationCall, + mZonesManagerPtr, _1, _2)); + + setSetActiveZoneCallback(std::bind(&ZonesManager::handleSetActiveZoneCall, + mZonesManagerPtr, _1, _2)); + + setCreateZoneCallback(std::bind(&ZonesManager::handleCreateZoneCall, + mZonesManagerPtr, _1, _2)); + + setDestroyZoneCallback(std::bind(&ZonesManager::handleDestroyZoneCall, + mZonesManagerPtr, _1, _2)); + + setShutdownZoneCallback(std::bind(&ZonesManager::handleShutdownZoneCall, + mZonesManagerPtr, _1, _2)); + + setStartZoneCallback(std::bind(&ZonesManager::handleStartZoneCall, + mZonesManagerPtr, _1, _2)); + + setLockZoneCallback(std::bind(&ZonesManager::handleLockZoneCall, + mZonesManagerPtr, _1, _2)); + + setUnlockZoneCallback(std::bind(&ZonesManager::handleUnlockZoneCall, + mZonesManagerPtr, _1, _2)); + + setGrantDeviceCallback(std::bind(&ZonesManager::handleGrantDeviceCall, + mZonesManagerPtr, _1, _2)); + + setRevokeDeviceCallback(std::bind(&ZonesManager::handleRevokeDeviceCall, + mZonesManagerPtr, _1, _2)); + + setNotifyActiveZoneCallback(std::bind(&ZonesManager::handleNotifyActiveZoneCall, + mZonesManagerPtr, "", _1, _2)); + + setSwitchToDefaultCallback(std::bind(&ZonesManager::handleSwitchToDefaultCall, + mZonesManagerPtr, "")); + + setFileMoveCallback(std::bind(&ZonesManager::handleFileMoveCall, + mZonesManagerPtr, "", _1, _2)); } HostIPCConnection::~HostIPCConnection() diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index b5d671e..3e4e7ff 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -33,6 +33,7 @@ namespace vasum { +class ZonesManager; class HostIPCConnection { public: @@ -47,11 +48,15 @@ public: typedef typename IPCSignalWrapper::type type; }; - HostIPCConnection(); + HostIPCConnection(ZonesManager* zm); ~HostIPCConnection(); - void setGetZoneConnectionsCallback(const Method::type& callback); + void signalZoneConnectionState(const api::ConnectionState& connectionState); + void sendNotification(const api::Notification& notification); + +private: void setGetZoneIdsCallback(const Method::type& callback); + void setGetZoneConnectionsCallback(const Method::type& callback); void setGetActiveZoneIdCallback(const Method::type& callback); void setGetZoneInfoCallback(const Method::type& callback); void setSetNetdevAttrsCallback(const Method::type& callback); @@ -80,12 +85,10 @@ public: void setSwitchToDefaultCallback(const Signal::type& callback); void setFileMoveCallback(const Method::type& callback); - void signalZoneConnectionState(const api::ConnectionState& connectionState); - void sendNotification(const api::Notification& notification); -private: ipc::epoll::ThreadDispatcher mDispatcher; std::unique_ptr mService; + ZonesManager* mZonesManagerPtr; }; } // namespace vasum diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 0762294..a66eff1 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -112,98 +112,14 @@ bool zoneIsRunning(const std::unique_ptr& zone) { } // namespace -template -void ZonesManager::setHandlers(Connection& connection) -{ - using namespace std::placeholders; - connection.setGetZoneIdsCallback(bind(&ZonesManager::handleGetZoneIdsCall, - this, _1)); - - connection.setGetActiveZoneIdCallback(bind(&ZonesManager::handleGetActiveZoneIdCall, - this, _1)); - - connection.setGetZoneInfoCallback(bind(&ZonesManager::handleGetZoneInfoCall, - this, _1, _2)); - - connection.setSetNetdevAttrsCallback(bind(&ZonesManager::handleSetNetdevAttrsCall, - this, _1, _2)); - - connection.setGetNetdevAttrsCallback(bind(&ZonesManager::handleGetNetdevAttrsCall, - this, _1, _2)); - - connection.setGetNetdevListCallback(bind(&ZonesManager::handleGetNetdevListCall, - this, _1, _2)); - - connection.setCreateNetdevVethCallback(bind(&ZonesManager::handleCreateNetdevVethCall, - this, _1, _2)); - - connection.setCreateNetdevMacvlanCallback(bind(&ZonesManager::handleCreateNetdevMacvlanCall, - this, _1, _2)); - - connection.setCreateNetdevPhysCallback(bind(&ZonesManager::handleCreateNetdevPhysCall, - this, _1, _2)); - - connection.setDestroyNetdevCallback(bind(&ZonesManager::handleDestroyNetdevCall, - this, _1, _2)); - - connection.setDeleteNetdevIpAddressCallback(bind(&ZonesManager::handleDeleteNetdevIpAddressCall, - this, _1, _2)); - - connection.setDeclareFileCallback(bind(&ZonesManager::handleDeclareFileCall, - this, _1, _2)); - - connection.setDeclareMountCallback(bind(&ZonesManager::handleDeclareMountCall, - this, _1, _2)); - - connection.setDeclareLinkCallback(bind(&ZonesManager::handleDeclareLinkCall, - this, _1, _2)); - - connection.setGetDeclarationsCallback(bind(&ZonesManager::handleGetDeclarationsCall, - this, _1, _2)); - - connection.setRemoveDeclarationCallback(bind(&ZonesManager::handleRemoveDeclarationCall, - this, _1, _2)); - - connection.setSetActiveZoneCallback(bind(&ZonesManager::handleSetActiveZoneCall, - this, _1, _2)); - - connection.setCreateZoneCallback(bind(&ZonesManager::handleCreateZoneCall, - this, _1, _2)); - - connection.setDestroyZoneCallback(bind(&ZonesManager::handleDestroyZoneCall, - this, _1, _2)); - - connection.setShutdownZoneCallback(bind(&ZonesManager::handleShutdownZoneCall, - this, _1, _2)); - - connection.setStartZoneCallback(bind(&ZonesManager::handleStartZoneCall, - this, _1, _2)); - - connection.setLockZoneCallback(bind(&ZonesManager::handleLockZoneCall, - this, _1, _2)); - - connection.setUnlockZoneCallback(bind(&ZonesManager::handleUnlockZoneCall, - this, _1, _2)); - - connection.setGrantDeviceCallback(bind(&ZonesManager::handleGrantDeviceCall, - this, _1, _2)); - - connection.setRevokeDeviceCallback(bind(&ZonesManager::handleRevokeDeviceCall, - this, _1, _2)); - - connection.setNotifyActiveZoneCallback(bind(&ZonesManager::handleNotifyActiveZoneCall, - this, "", _1, _2)); - - connection.setSwitchToDefaultCallback(bind(&ZonesManager::handleSwitchToDefaultCall, - this, "")); - - connection.setFileMoveCallback(bind(&ZonesManager::handleFileMoveCall, - this, "", _1, _2)); -} ZonesManager::ZonesManager(const std::string& configPath) : mWorker(utils::Worker::create()) + , mHostIPCConnection(this) , mDetachOnExit(false) +#ifdef DBUS_CONNECTION + , mHostDbusConnection(this) +#endif { LOGD("Instantiating ZonesManager object..."); @@ -213,13 +129,11 @@ ZonesManager::ZonesManager(const std::string& configPath) mDynamicConfig, getVasumDbPrefix()); - setHandlers(mHostIPCConnection); #ifdef DBUS_CONNECTION using namespace std::placeholders; mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules)); mHostDbusConnection.setProxyCallCallback(bind(&ZonesManager::handleProxyCall, this, HOST_ID, _1, _2, _3, _4, _5, _6, _7)); - setHandlers(mHostDbusConnection); #endif //DBUS_CONNECTION for (const auto& zoneId : mDynamicConfig.zoneIds) { @@ -237,8 +151,6 @@ ZonesManager::ZonesManager(const std::string& configPath) std::bind(&ZonesManager::switchingSequenceMonitorNotify, this))); } - - } ZonesManager::~ZonesManager() diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 2a2f6d7..c74f5ec 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -28,11 +28,12 @@ #include "zone.hpp" #include "zones-manager-config.hpp" -#include "host-ipc-connection.hpp" +#include "api/messages.hpp" #include "input-monitor.hpp" #include "utils/worker.hpp" #include "api/method-result-builder.hpp" +#include "host-ipc-connection.hpp" #ifdef DBUS_CONNECTION #include "host-dbus-connection.hpp" #include "proxy-call-policy.hpp" @@ -44,7 +45,6 @@ namespace vasum { - class ZonesManager final { public: @@ -115,62 +115,6 @@ public: */ void setZonesDetachOnExit(); -private: - typedef std::recursive_mutex Mutex; - typedef std::unique_lock Lock; - - utils::Worker::Pointer mWorker; - Mutex mMutex; // used to protect mZones - ZonesManagerConfig mConfig; //TODO make it const - ZonesManagerDynamicConfig mDynamicConfig; -#ifdef DBUS_CONNECTION - HostDbusConnection mHostDbusConnection; -#endif //DBUS_CONNECTION - HostIPCConnection mHostIPCConnection; - // to hold InputMonitor pointer to monitor if zone switching sequence is recognized - std::unique_ptr mSwitchingSequenceMonitor; - // like set but keep insertion order - // smart pointer is needed because Zone is not moveable (because of mutex) - typedef std::vector> Zones; - Zones mZones; - std::string mActiveZoneId; - bool mDetachOnExit; - - Zones::iterator findZone(const std::string& id); - Zone& getZone(const std::string& id); - Zones::iterator getRunningForegroundZoneIterator(); - Zones::iterator getNextToForegroundZoneIterator(); - void focusInternal(Zones::iterator iter); - - void saveDynamicConfig(); - void updateDefaultId(); - void refocus(); - void switchingSequenceMonitorNotify(); - void generateNewConfig(const std::string& id, - const std::string& templatePath); - std::string getTemplatePathForExistingZone(const std::string& id); - int getVTForNewZone(); - void insertZone(const std::string& zoneId, const std::string& templatePath); - - // Zone's handlers--------------------------------------------------------- - void handleNotifyActiveZoneCall(const std::string& caller, - const api::NotifActiveZoneIn& notif, - api::MethodResultBuilder::Pointer result); - void handleSwitchToDefaultCall(const std::string& caller); - void handleFileMoveCall(const std::string& srcZoneId, - const api::FileMoveRequestIn& request, - api::MethodResultBuilder::Pointer result); -#ifdef DBUS_CONNECTION - std::unique_ptr mProxyCallPolicy; - void handleProxyCall(const std::string& caller, - const std::string& target, - const std::string& targetBusName, - const std::string& targetObjectPath, - const std::string& targetInterface, - const std::string& targetMethod, - GVariant* parameters, - dbus::MethodResultBuilder::Pointer result); -#endif //DBUS_CONNECTION // Handlers -------------------------------------------------------- void handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result); void handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result); @@ -221,8 +165,61 @@ private: void handleRevokeDeviceCall(const api::RevokeDeviceIn& data, api::MethodResultBuilder::Pointer result); - template - void setHandlers(Connection& connnection); + // Zone's handlers--------------------------------------------------------- + void handleNotifyActiveZoneCall(const std::string& caller, + const api::NotifActiveZoneIn& notif, + api::MethodResultBuilder::Pointer result); + void handleSwitchToDefaultCall(const std::string& caller); + void handleFileMoveCall(const std::string& srcZoneId, + const api::FileMoveRequestIn& request, + api::MethodResultBuilder::Pointer result); + +private: + typedef std::recursive_mutex Mutex; + typedef std::unique_lock Lock; + + utils::Worker::Pointer mWorker; + Mutex mMutex; // used to protect mZones + ZonesManagerConfig mConfig; //TODO make it const + ZonesManagerDynamicConfig mDynamicConfig; + HostIPCConnection mHostIPCConnection; + // to hold InputMonitor pointer to monitor if zone switching sequence is recognized + std::unique_ptr mSwitchingSequenceMonitor; + // like set but keep insertion order + // smart pointer is needed because Zone is not moveable (because of mutex) + typedef std::vector> Zones; + Zones mZones; + std::string mActiveZoneId; + bool mDetachOnExit; + + Zones::iterator findZone(const std::string& id); + Zone& getZone(const std::string& id); + Zones::iterator getRunningForegroundZoneIterator(); + Zones::iterator getNextToForegroundZoneIterator(); + void focusInternal(Zones::iterator iter); + + void saveDynamicConfig(); + void updateDefaultId(); + void refocus(); + void switchingSequenceMonitorNotify(); + void generateNewConfig(const std::string& id, + const std::string& templatePath); + std::string getTemplatePathForExistingZone(const std::string& id); + int getVTForNewZone(); + void insertZone(const std::string& zoneId, const std::string& templatePath); + +#ifdef DBUS_CONNECTION + HostDbusConnection mHostDbusConnection; + std::unique_ptr mProxyCallPolicy; + void handleProxyCall(const std::string& caller, + const std::string& target, + const std::string& targetBusName, + const std::string& targetObjectPath, + const std::string& targetInterface, + const std::string& targetMethod, + GVariant* parameters, + dbus::MethodResultBuilder::Pointer result); +#endif //DBUS_CONNECTION }; diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 3e83884..ce02a33 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -30,6 +30,7 @@ #include "utils/latch.hpp" #include "utils/scoped-dir.hpp" #include "zones-manager.hpp" +#include "host-ipc-connection.hpp" #include "host-ipc-definitions.hpp" #include "logger/logger.hpp" -- 2.7.4 From 10a140ebdb5ab5c3482d26f569b1e84a4c3dc463 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 9 Jun 2015 10:55:03 +0200 Subject: [PATCH 10/16] Fix CMake variables [Bug] * systemd service/socket files should be in /usr/local/lib, while compiled libraries should reside in /usr/local/lib64 on 64-bit systems. * Two sockets were created - one by systemd service, one by vasum IPC mechanisms. [Cause] N/A [Solution] Rename vasum-ipc.socket to vasum.socket Correct variables regarding library and systemd file locations [Verification] Build, install, run tests, run vasum-cli, check file locations and service files. Change-Id: I54681eaebd00b1aec547617a2ea51b0675c24ec3 --- CMakeLists.txt | 12 ++++++++---- server/configs/CMakeLists.txt | 4 +++- server/configs/systemd/{vasum.socket => vasum.socket.in} | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) rename server/configs/systemd/{vasum.socket => vasum.socket.in} (73%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e865117..cbcf4b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,7 @@ IF(NOT DEFINED SYSCONF_INSTALL_DIR) ENDIF(NOT DEFINED SYSCONF_INSTALL_DIR) IF(NOT DEFINED LIB_INSTALL_DIR) - SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib") + SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") ENDIF(NOT DEFINED LIB_INSTALL_DIR) IF(NOT DEFINED INCLUDE_INSTALL_DIR) @@ -174,16 +174,20 @@ IF(NOT DEFINED SCRIPT_INSTALL_DIR) ENDIF(NOT DEFINED SCRIPT_INSTALL_DIR) IF(NOT DEFINED SYSTEMD_UNIT_DIR) - SET(SYSTEMD_UNIT_DIR "${LIB_INSTALL_DIR}/systemd/system") + SET(SYSTEMD_UNIT_DIR "${CMAKE_INSTALL_PREFIX}/lib/systemd/system") ENDIF(NOT DEFINED SYSTEMD_UNIT_DIR) IF(NOT DEFINED DATA_DIR) SET(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share") ENDIF(NOT DEFINED DATA_DIR) +IF(NOT DEFINED RUN_DIR) + SET(RUN_DIR "/var/run") +ENDIF(NOT DEFINED RUN_DIR) + SET(VSM_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/vasum) -SET(VSM_SERVER_IPC_SOCKET_PATH /var/run/vasum-ipc.socket) -SET(VSM_UNIT_TESTS_IPC_SOCKET_PATH /var/run/vasum-ipc-unit-tests.socket) +SET(VSM_SERVER_IPC_SOCKET_PATH ${RUN_DIR}/vasum.socket) +SET(VSM_UNIT_TESTS_IPC_SOCKET_PATH ${RUN_DIR}/vasum-ipc-unit-tests.socket) ADD_SUBDIRECTORY(${LOGGER_FOLDER}) ADD_SUBDIRECTORY(${DBUS_FOLDER}) diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 278a9fc..c57a806 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -25,6 +25,8 @@ FILE(GLOB lxc_templates_CONF templates/*.sh) ## Generate #################################################################### CONFIGURE_FILE(systemd/vasum.service.in ${CMAKE_BINARY_DIR}/systemd/vasum.service) +CONFIGURE_FILE(systemd/vasum.socket.in + ${CMAKE_BINARY_DIR}/systemd/vasum.socket) ## Install ##################################################################### @@ -51,5 +53,5 @@ INSTALL(PROGRAMS ${lxc_templates_CONF} INSTALL(FILES ${CMAKE_BINARY_DIR}/systemd/vasum.service - systemd/vasum.socket + ${CMAKE_BINARY_DIR}/systemd/vasum.socket DESTINATION ${SYSTEMD_UNIT_DIR}) diff --git a/server/configs/systemd/vasum.socket b/server/configs/systemd/vasum.socket.in similarity index 73% rename from server/configs/systemd/vasum.socket rename to server/configs/systemd/vasum.socket.in index 792935d..05bc66d 100644 --- a/server/configs/systemd/vasum.socket +++ b/server/configs/systemd/vasum.socket.in @@ -1,5 +1,5 @@ [Socket] -ListenStream=/run/vasum.socket +ListenStream=${VSM_SERVER_IPC_SOCKET_PATH} SocketMode=0755 SmackLabelIPIn=* SmackLabelIPOut=@ -- 2.7.4 From 03fed6bbca029b3d7c1c2954afdb997f22f24313 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 9 Jun 2015 15:18:29 +0200 Subject: [PATCH 11/16] Fix bash completion in case of user grep color aliases [Bug] Mitigate user grep aliases that use colors [Cause] N/A [Solution] Add --color=never to grep [Verification] Checked that bash completion works Change-Id: Ifffaf2e931f1cd573c6629a1932aca28b924509a --- cli/support/vasum-cli-completion.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/support/vasum-cli-completion.sh.in b/cli/support/vasum-cli-completion.sh.in index 79a5dad..18dda54 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 -e '^\S' | tail -n +3 | cut -f1 -d' ')" -- $cur)) + COMPREPLY=($(compgen -W "$(@CLI_CODENAME@ | grep --color=never -e '^\S' | tail -n +3 | cut -f1 -d' ')" -- $cur)) elif [ "$COMP_CWORD" == "2" ]; then COMPREPLY=($(compgen -W "-h" -- $cur)) fi -- 2.7.4 From a952476014d42a26feb4c99f5c48095bcf3d2ce7 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 10 Jun 2015 12:11:56 +0200 Subject: [PATCH 12/16] Remove unused function [Bug] Compile error [Cause] capget is static unused function [Solution] Remove capget [Verification] Compile with clang Change-Id: I3fb8e4b3de7f4bf4a02d3cb1c96009c3beb262c7 --- common/utils/environment.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp index 9614cfa..4a04e0d 100644 --- a/common/utils/environment.cpp +++ b/common/utils/environment.cpp @@ -72,15 +72,6 @@ static inline int capset(cap_user_header_t header, const cap_user_data_t data) #error "capset syscall isn't available" #endif -#ifdef __NR_capget -static inline int capget(cap_user_header_t header, cap_user_data_t data) -{ - return syscall(__NR_capget, header, data); -} -#else -#error "capget syscall isn't available" -#endif - using namespace utils; namespace { -- 2.7.4 From e681d41197e79fcef3007058b3d1b09cd130ef3f Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 9 Jun 2015 17:30:14 +0200 Subject: [PATCH 13/16] Fix for responding to a first request after socket activation [Bug] When socket activated the first request might not be properly handled because all the callback might not have registered yet. [Cause] N/A [Solution] Delayed handling requests until all the callbacks have been registered. [Verification] Built, installed, run tests. Did several tries with triggering socket activation: 1. systemctl start vasum.service 2. vasum-cli create_zone test 3. systemctl stop vasum.service 4. vasum-cli get_zone_ids 5. observe no error and list of zones should show 'test' 6. goto 3 Change-Id: I6de9742959d32afe68f496246065d3befc823955 --- server/host-ipc-connection.cpp | 11 +++++++---- server/host-ipc-connection.hpp | 1 + server/zones-manager.cpp | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index 1a003d4..e87adca 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -41,10 +41,6 @@ HostIPCConnection::HostIPCConnection(ZonesManager* zonesManagerPtr) LOGT("Connecting to host IPC socket"); mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET)); - LOGT("Starting IPC"); - mService->start(); - LOGD("Connected"); - using namespace std::placeholders; setGetZoneIdsCallback(std::bind(&ZonesManager::handleGetZoneIdsCall, mZonesManagerPtr, _1)); @@ -135,6 +131,13 @@ HostIPCConnection::~HostIPCConnection() { } +void HostIPCConnection::start() +{ + LOGT("Starting IPC"); + mService->start(); + LOGD("Connected"); +} + void HostIPCConnection::setGetZoneIdsCallback(const Method::type& callback) { typedef IPCMethodWrapper Callback; diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index 3e4e7ff..8107612 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -51,6 +51,7 @@ public: HostIPCConnection(ZonesManager* zm); ~HostIPCConnection(); + void start(); void signalZoneConnectionState(const api::ConnectionState& connectionState); void sendNotification(const api::Notification& notification); diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index a66eff1..7e0f641 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -151,6 +151,9 @@ ZonesManager::ZonesManager(const std::string& configPath) std::bind(&ZonesManager::switchingSequenceMonitorNotify, this))); } + + // After everything's initialized start to respond to clients' requests + mHostIPCConnection.start(); } ZonesManager::~ZonesManager() -- 2.7.4 From 3cce24ba314a579c5fedd44e75c00b737cedd304 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Wed, 10 Jun 2015 13:25:25 +0200 Subject: [PATCH 14/16] Remove ZoneAdmin class [Feature] Removed ZoneAdmin class [Cause] Unneeded layer between Zone class and LXC Zone [Solution] Remove ZoneAdmin class, move its functionality to Zone class [Verification] Build, install, run tests Change-Id: Id539ee2596c948f4cac6a0b9dff198d3d2b42c75 --- server/zone-admin.cpp | 323 ------------------------------ server/zone-admin.hpp | 192 ------------------ server/zone.cpp | 224 ++++++++++++++++++--- server/zone.hpp | 42 +++- server/zones-manager.cpp | 1 - tests/unit_tests/server/ut-zone-admin.cpp | 174 ---------------- tests/unit_tests/server/ut-zone.cpp | 95 ++++++++- 7 files changed, 314 insertions(+), 737 deletions(-) delete mode 100644 server/zone-admin.cpp delete mode 100644 server/zone-admin.hpp delete mode 100644 tests/unit_tests/server/ut-zone-admin.cpp diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp deleted file mode 100644 index 05d9c7d..0000000 --- a/server/zone-admin.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Jan Olszak - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -/** - * @file - * @author Jan Olszak (j.olszak@samsung.com) - * @brief Implementation of class for administrating one zone - */ - -#include "config.hpp" - -#include "zone-admin.hpp" -#include "exception.hpp" -#include "netdev.hpp" - -#include "logger/logger.hpp" -#include "utils/paths.hpp" -#include "utils/c-array.hpp" -#include "lxc/cgroup.hpp" - -#include -#include -#include -#include - - -namespace vasum { - -const std::uint64_t DEFAULT_CPU_SHARES = 1024; -const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000; - -ZoneAdmin::ZoneAdmin(const std::string& zoneId, - const std::string& zonesPath, - const std::string& zoneTemplateDir, - const ZoneConfig& config, - const ZoneDynamicConfig& dynamicConfig) - : mConfig(config), - mDynamicConfig(dynamicConfig), - mZone(zonesPath, zoneId), - mId(zoneId), - mDetachOnExit(false), - mDestroyOnExit(false) -{ - LOGD(mId << ": Instantiating ZoneAdmin object"); - - if (!mZone.isDefined()) { - - const std::string zoneTemplate = utils::getAbsolutePath(config.zoneTemplate, - zoneTemplateDir); - LOGI(mId << ": Creating zone from template: " << zoneTemplate); - utils::CStringArrayBuilder args; - if (!dynamicConfig.ipv4Gateway.empty()) { - args.add("--ipv4-gateway"); - args.add(dynamicConfig.ipv4Gateway.c_str()); - } - if (!dynamicConfig.ipv4.empty()) { - args.add("--ipv4"); - args.add(dynamicConfig.ipv4.c_str()); - } - const std::string vt = std::to_string(dynamicConfig.vt); - if (dynamicConfig.vt > 0) { - args.add("--vt"); - args.add(vt.c_str()); - } - if (!mZone.create(zoneTemplate, args.c_array())) { - throw ZoneOperationException("Could not create zone"); - } - } -} - - -ZoneAdmin::~ZoneAdmin() -{ - LOGD(mId << ": Destroying ZoneAdmin object..."); - - if (mDestroyOnExit) { - if (!mZone.stop()) { - LOGE(mId << ": Failed to stop the zone"); - } - if (!mZone.destroy()) { - LOGE(mId << ": Failed to destroy the zone"); - } - } - - if (!mDetachOnExit) { - // Try to forcefully stop - if (!mZone.stop()) { - LOGE(mId << ": Failed to stop the zone"); - } - } - - LOGD(mId << ": ZoneAdmin object destroyed"); -} - - -const std::string& ZoneAdmin::getId() const -{ - return mId; -} - - -void ZoneAdmin::start() -{ - LOGD(mId << ": Starting..."); - if (isRunning()) { - LOGD(mId << ": Already running - nothing to do..."); - return; - } - - utils::CStringArrayBuilder args; - for (const std::string& arg : mConfig.initWithArgs) { - args.add(arg.c_str()); - } - if (args.empty()) { - args.add("/sbin/init"); - } - - if (!mZone.start(args.c_array())) { - throw ZoneOperationException("Could not start zone"); - } - - // Wait until the full platform launch with graphical stack. - // VT should be activated by a graphical stack. - // If we do it with 'zoneToFocus.activateVT' before starting the graphical stack, - // graphical stack initialization failed and we finally switch to the black screen. - // Skip waiting when graphical stack is not running (unit tests). - if (mDynamicConfig.vt > 0) { - // TODO, timeout is a temporary solution - std::this_thread::sleep_for(std::chrono::milliseconds(4000)); - } - - LOGD(mId << ": Started"); -} - - -void ZoneAdmin::stop() -{ - LOGD(mId << ": Stopping procedure started..."); - if (isStopped()) { - LOGD(mId << ": Already crashed/down/off - nothing to do"); - return; - } - - if (!mZone.shutdown(mConfig.shutdownTimeout)) { - // force stop - if (!mZone.stop()) { - throw ZoneOperationException("Could not stop zone"); - } - } - - LOGD(mId << ": Stopping procedure ended"); -} - - -void ZoneAdmin::destroy() -{ - LOGD(mId << ": Destroying procedure started..."); - - if (!mZone.destroy()) { - throw ZoneOperationException("Could not destroy zone"); - } - - LOGD(mId << ": Destroying procedure ended"); -} - - -bool ZoneAdmin::isRunning() -{ - return mZone.getState() == lxc::LxcZone::State::RUNNING; -} - - -bool ZoneAdmin::isStopped() -{ - return mZone.getState() == lxc::LxcZone::State::STOPPED; -} - - -void ZoneAdmin::suspend() -{ - LOGD(mId << ": Pausing..."); - if (!mZone.freeze()) { - throw ZoneOperationException("Could not pause zone"); - } - LOGD(mId << ": Paused"); -} - - -void ZoneAdmin::resume() -{ - LOGD(mId << ": Resuming..."); - if (!mZone.unfreeze()) { - throw ZoneOperationException("Could not resume zone"); - } - LOGD(mId << ": Resumed"); -} - - -bool ZoneAdmin::isPaused() -{ - return mZone.getState() == lxc::LxcZone::State::FROZEN; -} - - -void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched) -{ - assert(isRunning()); - - switch (sched) { - case SchedulerLevel::FOREGROUND: - LOGD(mId << ": Setting SchedulerLevel::FOREGROUND"); - setSchedulerParams(DEFAULT_CPU_SHARES, - DEFAULT_VCPU_PERIOD_MS, - mConfig.cpuQuotaForeground); - break; - case SchedulerLevel::BACKGROUND: - LOGD(mId << ": Setting SchedulerLevel::BACKGROUND"); - setSchedulerParams(DEFAULT_CPU_SHARES, - DEFAULT_VCPU_PERIOD_MS, - mConfig.cpuQuotaBackground); - break; - default: - assert(0 && "Unknown sched parameter value"); - } -} - - -void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares, - std::uint64_t vcpuPeriod, - std::int64_t vcpuQuota) -{ - assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000); - assert(vcpuQuota == -1 || - (vcpuQuota >= 1000 && vcpuQuota <= static_cast(ULLONG_MAX / 1000))); - - if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) || - !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) || - !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) { - - LOGE(mId << ": Error while setting the zone's scheduler params"); - throw ZoneOperationException("Could not set scheduler params"); - } -} - -void ZoneAdmin::setDetachOnExit() -{ - mDetachOnExit = true; -} - -void ZoneAdmin::setDestroyOnExit() -{ - mDestroyOnExit = true; -} - -std::int64_t ZoneAdmin::getSchedulerQuota() -{ - std::string ret; - if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) { - LOGE(mId << ": Error while getting the zone's scheduler quota param"); - throw ZoneOperationException("Could not get scheduler quota param"); - } - return std::stoll(ret); -} - -void ZoneAdmin::createNetdevVeth(const std::string& zoneDev, - const std::string& hostDev) -{ - netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev); -} - -void ZoneAdmin::createNetdevMacvlan(const std::string& zoneDev, - const std::string& hostDev, - const uint32_t& mode) -{ - netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast(mode)); -} - -void ZoneAdmin::moveNetdev(const std::string& devId) -{ - netdev::movePhys(mZone.getInitPid(), devId); -} - -void ZoneAdmin::destroyNetdev(const std::string& devId) -{ - netdev::destroyNetdev(devId, mZone.getInitPid()); -} - -void ZoneAdmin::setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs) -{ - netdev::setAttrs(mZone.getInitPid(), netdev, attrs); -} - -ZoneAdmin::NetdevAttrs ZoneAdmin::getNetdevAttrs(const std::string& netdev) -{ - return netdev::getAttrs(mZone.getInitPid(), netdev); -} - -std::vector ZoneAdmin::getNetdevList() -{ - return netdev::listNetdev(mZone.getInitPid()); -} - -void ZoneAdmin::deleteNetdevIpAddress(const std::string& netdev, const std::string& ip) -{ - netdev::deleteIpAddress(mZone.getInitPid(), netdev, ip); -} - -} // namespace vasum diff --git a/server/zone-admin.hpp b/server/zone-admin.hpp deleted file mode 100644 index ec4c7cd..0000000 --- a/server/zone-admin.hpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Jan Olszak - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -/** - * @file - * @author Jan Olszak (j.olszak@samsung.com) - * @brief Declaration of the class for administrating one zone - */ - - -#ifndef SERVER_ZONE_ADMIN_HPP -#define SERVER_ZONE_ADMIN_HPP - -#include "zone-config.hpp" -#include "lxc/zone.hpp" -#include "netdev.hpp" - -namespace vasum { - - -enum class SchedulerLevel { - FOREGROUND, - BACKGROUND -}; - -class ZoneAdmin { - -public: - typedef netdev::Attrs NetdevAttrs; - - /** - * ZoneAdmin constructor - * @param zoneId zone id - * @param zonesPath directory where zones are defined (configs, rootfs etc) - * @param zoneTemplateDir directory where templates are stored - * @param config zones config - * @param dynamicConfig zones dynamic config - */ - ZoneAdmin(const std::string& zoneId, - const std::string& zonesPath, - const std::string& zoneTemplateDir, - const ZoneConfig& config, - const ZoneDynamicConfig& dynamicConfig); - virtual ~ZoneAdmin(); - - /** - * Get the zone id - */ - const std::string& getId() const; - - /** - * Boot the zone to the background. - */ - void start(); - - /** - * Try to shutdown the zone, if failed, kill it. - */ - void stop(); - - /** - * Destroy stopped zone. In particular it removes whole zones rootfs. - */ - void destroy(); - - /** - * @return Is the zone running? - */ - bool isRunning(); - - /** - * Check if the zone is stopped. It's NOT equivalent to !isRunning, - * because it checks different internal zone states. There are other states, - * (e.g. paused) when the zone isn't running nor stopped. - * - * @return Is the zone stopped? - */ - bool isStopped(); - - /** - * Suspends an active zone, the process is frozen - * without further access to CPU resources and I/O, - * but the memory used by the zone - * at the hypervisor level will stay allocated - */ - void suspend(); - - /** - * Resume the zone after suspension. - */ - void resume(); - - /** - * @return Is the zone in a paused state? - */ - bool isPaused(); - - /** - * Sets the zones scheduler CFS quota. - */ - void setSchedulerLevel(SchedulerLevel sched); - - /** - * Set whether zone should be detached on exit. - */ - void setDetachOnExit(); - - /** - * Set if zone should be destroyed on exit. - */ - void setDestroyOnExit(); - - /** - * @return Scheduler CFS quota, - * TODO: this function is only for UNIT TESTS - */ - std::int64_t getSchedulerQuota(); - - /** - * Create veth network device - */ - void createNetdevVeth(const std::string& zoneDev, - const std::string& hostDev); - - /** - * Create macvlan network device - */ - void createNetdevMacvlan(const std::string& zoneDev, - const std::string& hostDev, - const uint32_t& mode); - - /** - * Move network device to zone - */ - void moveNetdev(const std::string& devId); - - /** - * Destroy network device in zone - */ - void destroyNetdev(const std::string& devId); - - /** - * Set network device attributes - */ - void setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs); - - /** - * Get network device attributes - */ - NetdevAttrs getNetdevAttrs(const std::string& netdev); - - /** - * Get network device list - */ - std::vector getNetdevList(); - - /** - * Remove ipv4/ipv6 address from network device - */ - void deleteNetdevIpAddress(const std::string& netdev, const std::string& ip); - -private: - const ZoneConfig& mConfig; - const ZoneDynamicConfig& mDynamicConfig; - lxc::LxcZone mZone; - const std::string mId; - bool mDetachOnExit; - bool mDestroyOnExit; - - void setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota); -}; - - -} // namespace vasum - - -#endif // SERVER_ZONE_ADMIN_HPP diff --git a/server/zone.cpp b/server/zone.cpp index 3fe0b12..94f6873 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -26,17 +26,22 @@ #include "zone.hpp" #include "dynamic-config-scheme.hpp" -#include "base-exception.hpp" +#include "exception.hpp" #include "logger/logger.hpp" #include "utils/paths.hpp" #include "utils/vt.hpp" +#include "utils/c-array.hpp" +#include "lxc/cgroup.hpp" #include "config/manager.hpp" #include +#include +#include #include #include +#include namespace vasum { @@ -50,6 +55,9 @@ const std::string STATE_STOPPED = "stopped"; const std::string STATE_RUNNING = "running"; const std::string STATE_PAUSED = "paused"; +const std::uint64_t DEFAULT_CPU_SHARES = 1024; +const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000; + } // namespace Zone::Zone(const std::string& zoneId, @@ -59,7 +67,13 @@ Zone::Zone(const std::string& zoneId, const std::string& zoneTemplateDir, const std::string& baseRunMountPointPath) : mDbPath(dbPath) + , mZone(zonesPath, zoneId) + , mId(zoneId) + , mDetachOnExit(false) + , mDestroyOnExit(false) { + LOGD(mId << ": Instantiating Zone object"); + const std::string dbPrefix = getZoneDbPrefix(zoneId); config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mConfig, dbPrefix); config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mDynamicConfig, dbPrefix); @@ -75,7 +89,28 @@ Zone::Zone(const std::string& zoneId, mRunMountPoint = fs::absolute(mDynamicConfig.runMountPoint, baseRunMountPointPath).string(); } - mAdmin.reset(new ZoneAdmin(zoneId, zonesPath, zoneTemplateDir, mConfig, mDynamicConfig)); + if (!mZone.isDefined()) { + const std::string zoneTemplate = utils::getAbsolutePath(mConfig.zoneTemplate, + zoneTemplateDir); + LOGI(mId << ": Creating zone from template: " << zoneTemplate); + utils::CStringArrayBuilder args; + if (!mDynamicConfig.ipv4Gateway.empty()) { + args.add("--ipv4-gateway"); + args.add(mDynamicConfig.ipv4Gateway.c_str()); + } + if (!mDynamicConfig.ipv4.empty()) { + args.add("--ipv4"); + args.add(mDynamicConfig.ipv4.c_str()); + } + const std::string vt = std::to_string(mDynamicConfig.vt); + if (mDynamicConfig.vt > 0) { + args.add("--vt"); + args.add(vt.c_str()); + } + if (!mZone.create(zoneTemplate, args.c_array())) { + throw ZoneOperationException("Could not create zone"); + } + } const fs::path zonePath = fs::path(zonesPath) / zoneId; mRootPath = (zonePath / fs::path("rootfs")).string(); @@ -83,6 +118,29 @@ Zone::Zone(const std::string& zoneId, mProvision.reset(new ZoneProvision(mRootPath, zoneTemplatePath, dbPath, dbPrefix, mConfig.validLinkPrefixes)); } +Zone::~Zone() +{ + LOGD(mId << ": Destroying Zone object..."); + + if (mDestroyOnExit) { + if (!mZone.stop()) { + LOGE(mId << ": Failed to stop the zone"); + } + if (!mZone.destroy()) { + LOGE(mId << ": Failed to destroy the zone"); + } + } + + if (!mDetachOnExit && !mDestroyOnExit) { + // Try to forcefully stop + if (!mZone.stop()) { + LOGE(mId << ": Failed to stop the zone"); + } + } + + LOGD(mId << ": Zone object destroyed"); +} + const std::vector& Zone::getPermittedToSend() const { return mPermittedToSend; @@ -96,7 +154,7 @@ const std::vector& Zone::getPermittedToRecv() const const std::string& Zone::getId() const { Lock lock(mReconnectMutex); - return mAdmin->getId(); + return mId; } int Zone::getPrivilege() const @@ -106,14 +164,14 @@ int Zone::getPrivilege() const void Zone::saveDynamicConfig() { - config::saveToKVStore(mDbPath, mDynamicConfig, getZoneDbPrefix(getId())); + config::saveToKVStore(mDbPath, mDynamicConfig, getZoneDbPrefix(mId)); } void Zone::updateRequestedState(const std::string& state) { // assume mutex is locked if (state != mDynamicConfig.requestedState) { - LOGT("Set requested state of " << getId() << " to " << state); + LOGT("Set requested state of " << mId << " to " << state); mDynamicConfig.requestedState = state; saveDynamicConfig(); } @@ -125,7 +183,7 @@ void Zone::restore() { Lock lock(mReconnectMutex); requestedState = mDynamicConfig.requestedState; - LOGT("Requested state of " << getId() << ": " << requestedState); + LOGT("Requested state of " << mId << ": " << requestedState); } if (requestedState == STATE_RUNNING) { @@ -143,9 +201,41 @@ void Zone::restore() void Zone::start() { Lock lock(mReconnectMutex); + + LOGD(mId << ": Starting..."); + updateRequestedState(STATE_RUNNING); mProvision->start(); - mAdmin->start(); + + if (isRunning()) { + LOGD(mId << ": Already running - nothing to do..."); + return; + } + + utils::CStringArrayBuilder args; + for (const std::string& arg : mConfig.initWithArgs) { + args.add(arg.c_str()); + } + if (args.empty()) { + args.add("/sbin/init"); + } + + if (!mZone.start(args.c_array())) { + throw ZoneOperationException("Could not start zone"); + } + + // Wait until the full platform launch with graphical stack. + // VT should be activated by a graphical stack. + // If we do it with 'zoneToFocus.activateVT' before starting the graphical stack, + // graphical stack initialization failed and we finally switch to the black screen. + // Skip waiting when graphical stack is not running (unit tests). + if (mDynamicConfig.vt > 0) { + // TODO, timeout is a temporary solution + std::this_thread::sleep_for(std::chrono::milliseconds(4000)); + } + + LOGD(mId << ": Started"); + // Increase cpu quota before connect, otherwise it'd take ages. goForeground(); // refocus in ZonesManager will adjust cpu quota after all @@ -154,15 +244,32 @@ void Zone::start() void Zone::stop(bool saveState) { Lock lock(mReconnectMutex); + + LOGD(mId << ": Stopping procedure started..."); + if (saveState) { updateRequestedState(STATE_STOPPED); } - if (mAdmin->isRunning()) { + if (isRunning()) { // boost stopping goForeground(); } - mAdmin->stop(); + + if (isStopped()) { + LOGD(mId << ": Already crashed/down/off - nothing to do"); + return; + } + + if (!mZone.shutdown(mConfig.shutdownTimeout)) { + // force stop + if (!mZone.stop()) { + throw ZoneOperationException("Could not stop zone"); + } + } + mProvision->stop(); + + LOGD(mId << ": Stopping procedure ended"); } int Zone::getVT() const @@ -191,7 +298,7 @@ void Zone::createNetdevVeth(const std::string& zoneDev, const std::string& hostDev) { Lock lock(mReconnectMutex); - mAdmin->createNetdevVeth(zoneDev, hostDev); + netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev); } void Zone::createNetdevMacvlan(const std::string& zoneDev, @@ -199,75 +306,87 @@ void Zone::createNetdevMacvlan(const std::string& zoneDev, const uint32_t& mode) { Lock lock(mReconnectMutex); - mAdmin->createNetdevMacvlan(zoneDev, hostDev, mode); + netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast(mode)); } void Zone::moveNetdev(const std::string& devId) { Lock lock(mReconnectMutex); - mAdmin->moveNetdev(devId); + netdev::movePhys(mZone.getInitPid(), devId); } void Zone::destroyNetdev(const std::string& devId) { Lock lock(mReconnectMutex); - mAdmin->destroyNetdev(devId); + netdev::destroyNetdev(devId, mZone.getInitPid()); } void Zone::goForeground() { Lock lock(mReconnectMutex); - mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND); + setSchedulerLevel(SchedulerLevel::FOREGROUND); } void Zone::goBackground() { Lock lock(mReconnectMutex); - mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND); + setSchedulerLevel(SchedulerLevel::BACKGROUND); } void Zone::setDetachOnExit() { Lock lock(mReconnectMutex); - mAdmin->setDetachOnExit(); + mDetachOnExit = true; } void Zone::setDestroyOnExit() { Lock lock(mReconnectMutex); - mAdmin->setDestroyOnExit(); + mDestroyOnExit = true; } bool Zone::isRunning() { Lock lock(mReconnectMutex); - return mAdmin->isRunning(); + return mZone.getState() == lxc::LxcZone::State::RUNNING; } bool Zone::isStopped() { Lock lock(mReconnectMutex); - return mAdmin->isStopped(); + return mZone.getState() == lxc::LxcZone::State::STOPPED; } void Zone::suspend() { Lock lock(mReconnectMutex); - mAdmin->suspend(); + + LOGD(mId << ": Pausing..."); + if (!mZone.freeze()) { + throw ZoneOperationException("Could not pause zone"); + } + LOGD(mId << ": Paused"); + updateRequestedState(STATE_PAUSED); } void Zone::resume() { Lock lock(mReconnectMutex); - mAdmin->resume(); + + LOGD(mId << ": Resuming..."); + if (!mZone.unfreeze()) { + throw ZoneOperationException("Could not resume zone"); + } + LOGD(mId << ": Resumed"); + updateRequestedState(STATE_RUNNING); } bool Zone::isPaused() { Lock lock(mReconnectMutex); - return mAdmin->isPaused(); + return mZone.getState() == lxc::LxcZone::State::FROZEN; } bool Zone::isSwitchToDefaultAfterTimeoutAllowed() const @@ -308,28 +427,77 @@ void Zone::removeDeclaration(const std::string& declarationId) mProvision->remove(declarationId); } -void Zone::setNetdevAttrs(const std::string& netdev, const ZoneAdmin::NetdevAttrs& attrs) +void Zone::setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs) { Lock lock(mReconnectMutex); - mAdmin->setNetdevAttrs(netdev, attrs); + netdev::setAttrs(mZone.getInitPid(), netdev, attrs); } -ZoneAdmin::NetdevAttrs Zone::getNetdevAttrs(const std::string& netdev) +Zone::NetdevAttrs Zone::getNetdevAttrs(const std::string& netdev) { Lock lock(mReconnectMutex); - return mAdmin->getNetdevAttrs(netdev); + return netdev::getAttrs(mZone.getInitPid(), netdev); } std::vector Zone::getNetdevList() { Lock lock(mReconnectMutex); - return mAdmin->getNetdevList(); + return netdev::listNetdev(mZone.getInitPid()); } void Zone::deleteNetdevIpAddress(const std::string& netdev, const std::string& ip) { Lock lock(mReconnectMutex); - mAdmin->deleteNetdevIpAddress(netdev, ip); + netdev::deleteIpAddress(mZone.getInitPid(), netdev, ip); +} + +std::int64_t Zone::getSchedulerQuota() +{ + std::string ret; + if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) { + LOGE(mId << ": Error while getting the zone's scheduler quota param"); + throw ZoneOperationException("Could not get scheduler quota param"); + } + return std::stoll(ret); +} + +void Zone::setSchedulerLevel(SchedulerLevel sched) +{ + assert(isRunning()); + + switch (sched) { + case SchedulerLevel::FOREGROUND: + LOGD(mId << ": Setting SchedulerLevel::FOREGROUND"); + setSchedulerParams(DEFAULT_CPU_SHARES, + DEFAULT_VCPU_PERIOD_MS, + mConfig.cpuQuotaForeground); + break; + case SchedulerLevel::BACKGROUND: + LOGD(mId << ": Setting SchedulerLevel::BACKGROUND"); + setSchedulerParams(DEFAULT_CPU_SHARES, + DEFAULT_VCPU_PERIOD_MS, + mConfig.cpuQuotaBackground); + break; + default: + assert(0 && "Unknown sched parameter value"); + } +} + +void Zone::setSchedulerParams(std::uint64_t cpuShares, + std::uint64_t vcpuPeriod, + std::int64_t vcpuQuota) +{ + assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000); + assert(vcpuQuota == -1 || + (vcpuQuota >= 1000 && vcpuQuota <= static_cast(ULLONG_MAX / 1000))); + + if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) || + !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) || + !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) { + + LOGE(mId << ": Error while setting the zone's scheduler params"); + throw ZoneOperationException("Could not set scheduler params"); + } } } // namespace vasum diff --git a/server/zone.hpp b/server/zone.hpp index fb9f0c7..0829c35 100644 --- a/server/zone.hpp +++ b/server/zone.hpp @@ -27,9 +27,11 @@ #define SERVER_ZONE_HPP #include "zone-config.hpp" -#include "zone-admin.hpp" #include "zone-provision.hpp" +#include "lxc/zone.hpp" +#include "netdev.hpp" + #include #include #include @@ -40,9 +42,16 @@ namespace vasum { +enum class SchedulerLevel { + FOREGROUND, + BACKGROUND +}; + class Zone { public: + typedef netdev::Attrs NetdevAttrs; + /** * Zone constructor * @param zoneId zone id @@ -60,6 +69,7 @@ public: const std::string& baseRunMountPointPath); Zone(const Zone&) = delete; Zone& operator=(const Zone&) = delete; + ~Zone(); typedef std::function StartAsyncResultCallback; @@ -75,8 +85,6 @@ public: */ const std::vector& getPermittedToRecv() const; - // ZoneAdmin API - /** * Get the zone id */ @@ -124,8 +132,6 @@ public: /** * Set if zone should be detached on exit. - * - * This sends detach flag to ZoneAdmin object. */ void setDetachOnExit(); @@ -149,7 +155,10 @@ public: bool isStopped(); /** - * Suspend zone. + * Suspends an active zone, the process is frozen + * without further access to CPU resources and I/O, + * but the memory used by the zone + * at the hypervisor level will stay allocated */ void suspend(); @@ -235,12 +244,12 @@ public: /** * Set network device attributes */ - void setNetdevAttrs(const std::string& netdev, const ZoneAdmin::NetdevAttrs& attrs); + void setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs); /** * Get network device attributes */ - ZoneAdmin::NetdevAttrs getNetdevAttrs(const std::string& netdev); + NetdevAttrs getNetdevAttrs(const std::string& netdev); /** * Get network device list @@ -252,21 +261,36 @@ public: */ void deleteNetdevIpAddress(const std::string& netdev, const std::string& ip); + /** + * Sets the zones scheduler CFS quota. + */ + void setSchedulerLevel(SchedulerLevel sched); + + /** + * @return Scheduler CFS quota, + * TODO: this function is only for UNIT TESTS + */ + std::int64_t getSchedulerQuota(); + private: ZoneConfig mConfig; ZoneDynamicConfig mDynamicConfig; std::vector mPermittedToSend; std::vector mPermittedToRecv; - std::unique_ptr mAdmin; std::unique_ptr mProvision; mutable std::recursive_mutex mReconnectMutex; std::string mRunMountPoint; std::string mRootPath; std::string mDbPath; + lxc::LxcZone mZone; + const std::string mId; + bool mDetachOnExit; + bool mDestroyOnExit; void onNameLostCallback(); void saveDynamicConfig(); void updateRequestedState(const std::string& state); + void setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota); }; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 7e0f641..a34dbe9 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -27,7 +27,6 @@ #include "common-definitions.hpp" #include "dynamic-config-scheme.hpp" #include "zones-manager.hpp" -#include "zone-admin.hpp" #include "lxc/cgroup.hpp" #include "exception.hpp" diff --git a/tests/unit_tests/server/ut-zone-admin.cpp b/tests/unit_tests/server/ut-zone-admin.cpp deleted file mode 100644 index faee59a..0000000 --- a/tests/unit_tests/server/ut-zone-admin.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Jan Olszak - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - - -/** - * @file - * @author Jan Olszak (j.olszak@samsung.com) - * @brief Unit tests of the ZoneAdmin class - */ - -#include "config.hpp" -#include "ut.hpp" - -#include "zone-admin.hpp" -#include "exception.hpp" - -#include "utils/glib-loop.hpp" -#include "utils/scoped-dir.hpp" -#include "config/manager.hpp" - -using namespace vasum; - -namespace { - -const std::string TEMPLATES_DIR = VSM_TEST_TEMPLATES_INSTALL_DIR; -const std::string TEST_CONFIG_PATH = TEMPLATES_DIR + "/default.conf"; -const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = TEMPLATES_DIR + "/test-no-shutdown.conf"; -const std::string BUGGY_CONFIG_PATH = TEMPLATES_DIR + "/buggy-init.conf"; -const std::string MISSING_CONFIG_PATH = TEMPLATES_DIR + "/missing.conf"; -const std::string ZONES_PATH = "/tmp/ut-zones"; - -struct Fixture { - utils::ScopedGlibLoop mLoop; - utils::ScopedDir mZonesPathGuard; - - ZoneConfig mConfig; - ZoneDynamicConfig mDynamicConfig; - - Fixture() - : mZonesPathGuard(ZONES_PATH) - {} - - std::unique_ptr create(const std::string& configPath) - { - config::loadFromJsonFile(configPath, mConfig); - config::loadFromJsonFile(configPath, mDynamicConfig); - return std::unique_ptr(new ZoneAdmin("zoneId", - ZONES_PATH, - TEMPLATES_DIR, - mConfig, - mDynamicConfig)); - } - - void ensureStarted() - { - // wait for zones init to fully start - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } -}; - -} // namespace - - -BOOST_FIXTURE_TEST_SUITE(ZoneAdminSuite, Fixture) - -BOOST_AUTO_TEST_CASE(ConstructorDestructor) -{ - auto admin = create(TEST_CONFIG_PATH); - admin.reset(); -} - -BOOST_AUTO_TEST_CASE(MissingConfig) -{ - BOOST_REQUIRE_EXCEPTION(create(MISSING_CONFIG_PATH), - ZoneOperationException, - WhatEquals("Could not create zone")); -} - -BOOST_AUTO_TEST_CASE(Start) -{ - auto admin = create(TEST_CONFIG_PATH); - - admin->start(); - ensureStarted(); - - BOOST_CHECK(admin->isRunning()); -} - -BOOST_AUTO_TEST_CASE(StartBuggy) -{ - auto admin = create(BUGGY_CONFIG_PATH); - BOOST_REQUIRE_EXCEPTION(admin->start(), - ZoneOperationException, - WhatEquals("Could not start zone")); -} - -BOOST_AUTO_TEST_CASE(StopShutdown) -{ - auto admin = create(TEST_CONFIG_PATH); - - admin->start(); - ensureStarted(); - BOOST_REQUIRE(admin->isRunning()); - - admin->stop(); - BOOST_CHECK(!admin->isRunning()); - BOOST_CHECK(admin->isStopped()); -} - -// This test needs to wait for a shutdown timer in stop() method. This takes 10s+. -BOOST_AUTO_TEST_CASE(StopDestroy) -{ - auto admin = create(TEST_NO_SHUTDOWN_CONFIG_PATH); - - admin->start(); - ensureStarted(); - BOOST_REQUIRE(admin->isRunning()); - - admin->stop(); - BOOST_CHECK(!admin->isRunning()); - BOOST_CHECK(admin->isStopped()); -} - -BOOST_AUTO_TEST_CASE(SuspendResume) -{ - auto admin = create(TEST_NO_SHUTDOWN_CONFIG_PATH); - - admin->start(); - ensureStarted(); - BOOST_REQUIRE(admin->isRunning()); - - admin->suspend(); - BOOST_CHECK(!admin->isRunning()); - BOOST_CHECK(!admin->isStopped()); - BOOST_CHECK(admin->isPaused()); - - admin->resume(); - BOOST_CHECK(!admin->isPaused()); - BOOST_CHECK(!admin->isStopped()); - BOOST_CHECK(admin->isRunning()); -} - -BOOST_AUTO_TEST_CASE(ForegroundBackgroundSchedulerLevel) -{ - auto admin = create(TEST_CONFIG_PATH); - - BOOST_REQUIRE(mConfig.cpuQuotaForeground != mConfig.cpuQuotaBackground); - - admin->start(); - ensureStarted(); - - admin->setSchedulerLevel(SchedulerLevel::FOREGROUND); - BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaForeground); - - admin->setSchedulerLevel(SchedulerLevel::BACKGROUND); - BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaBackground); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp index abc10dc..1da6190 100644 --- a/tests/unit_tests/server/ut-zone.cpp +++ b/tests/unit_tests/server/ut-zone.cpp @@ -33,6 +33,7 @@ #include "utils/exception.hpp" #include "utils/glib-loop.hpp" #include "utils/scoped-dir.hpp" +#include "config/manager.hpp" #include "config/exception.hpp" #include "netdev.hpp" @@ -54,8 +55,10 @@ namespace { const std::string TEMPLATES_DIR = VSM_TEST_TEMPLATES_INSTALL_DIR; const std::string TEST_CONFIG_PATH = TEMPLATES_DIR + "/default.conf"; +const std::string TEST_NO_SHUTDOWN_CONFIG_PATH = TEMPLATES_DIR + "/test-no-shutdown.conf"; const std::string TEST_DBUS_CONFIG_PATH = TEMPLATES_DIR + "/console-dbus.conf"; const std::string BUGGY_CONFIG_PATH = TEMPLATES_DIR + "/buggy-template.conf"; +const std::string BUGGY_INIT_CONFIG_PATH = TEMPLATES_DIR + "/buggy-init.conf"; const std::string MISSING_CONFIG_PATH = TEMPLATES_DIR + "/missing-config.conf"; const std::string ZONES_PATH = "/tmp/ut-zones"; const std::string DB_PATH = ZONES_PATH + "/vasum.db"; @@ -144,6 +147,78 @@ BOOST_AUTO_TEST_CASE(StartStop) c->stop(true); } +BOOST_AUTO_TEST_CASE(StartBuggyInit) +{ + auto c = create(BUGGY_INIT_CONFIG_PATH); + BOOST_REQUIRE_EXCEPTION(c->start(), + ZoneOperationException, + WhatEquals("Could not start zone")); +} + +BOOST_AUTO_TEST_CASE(StopShutdown) +{ + auto c = create(TEST_CONFIG_PATH); + + c->start(); + ensureStarted(); + BOOST_REQUIRE(c->isRunning()); + + c->stop(true); + BOOST_CHECK(!c->isRunning()); + BOOST_CHECK(c->isStopped()); +} + +// This test needs to wait for a shutdown timer in stop() method. This takes 10s+. +BOOST_AUTO_TEST_CASE(StopDestroy) +{ + auto c = create(TEST_NO_SHUTDOWN_CONFIG_PATH); + + c->start(); + ensureStarted(); + BOOST_REQUIRE(c->isRunning()); + + c->stop(true); + BOOST_CHECK(!c->isRunning()); + BOOST_CHECK(c->isStopped()); +} + +BOOST_AUTO_TEST_CASE(SuspendResume) +{ + auto c = create(TEST_NO_SHUTDOWN_CONFIG_PATH); + + c->start(); + ensureStarted(); + BOOST_REQUIRE(c->isRunning()); + + c->suspend(); + BOOST_CHECK(!c->isRunning()); + BOOST_CHECK(!c->isStopped()); + BOOST_CHECK(c->isPaused()); + + c->resume(); + BOOST_CHECK(!c->isPaused()); + BOOST_CHECK(!c->isStopped()); + BOOST_CHECK(c->isRunning()); +} + +BOOST_AUTO_TEST_CASE(ForegroundBackgroundSchedulerLevel) +{ + auto c = create(TEST_CONFIG_PATH); + ZoneConfig refConfig; + config::loadFromJsonFile(TEST_CONFIG_PATH, refConfig); + + BOOST_REQUIRE(refConfig.cpuQuotaForeground != refConfig.cpuQuotaBackground); + + c->start(); + ensureStarted(); + + c->setSchedulerLevel(SchedulerLevel::FOREGROUND); + BOOST_CHECK_EQUAL(c->getSchedulerQuota(), refConfig.cpuQuotaForeground); + + c->setSchedulerLevel(SchedulerLevel::BACKGROUND); + BOOST_CHECK_EQUAL(c->getSchedulerQuota(), refConfig.cpuQuotaBackground); +} + BOOST_AUTO_TEST_CASE(DbusConnection) { mRunGuard.create("/tmp/ut-run"); // the same path as in zone template @@ -214,7 +289,7 @@ BOOST_AUTO_TEST_CASE(GetNetdevAttrs) c->start(); ensureStarted(); c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); - ZoneAdmin::NetdevAttrs attrs = c->getNetdevAttrs(ZONE_NETDEV); + Zone::NetdevAttrs attrs = c->getNetdevAttrs(ZONE_NETDEV); bool gotMtu = false; bool gotFlags = false; bool gotType = false; @@ -246,12 +321,12 @@ BOOST_AUTO_TEST_CASE(SetNetdevAttrs) c->start(); ensureStarted(); c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); - ZoneAdmin::NetdevAttrs attrsIn; + Zone::NetdevAttrs attrsIn; attrsIn.push_back(std::make_tuple("mtu", "500")); c->setNetdevAttrs(ZONE_NETDEV, attrsIn); bool gotMtu = false; - ZoneAdmin::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); + Zone::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); for (auto& attr : attrsOut) { if (std::get<0>(attr) == "mtu") { BOOST_CHECK(!gotMtu); @@ -275,11 +350,11 @@ BOOST_AUTO_TEST_CASE(SetNetdevIpv4) c->start(); ensureStarted(); c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); - ZoneAdmin::NetdevAttrs attrsIn; + Zone::NetdevAttrs attrsIn; attrsIn.push_back(std::make_tuple("ipv4", "ip:192.168.4.1,prefixlen:24")); c->setNetdevAttrs(ZONE_NETDEV, attrsIn); - ZoneAdmin::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); + Zone::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); int gotIp = 0; for (auto& attr : attrsOut) { if (std::get<0>(attr) == "ipv4") { @@ -315,11 +390,11 @@ BOOST_AUTO_TEST_CASE(SetNetdevIpv6) c->start(); ensureStarted(); c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); - ZoneAdmin::NetdevAttrs attrsIn; + Zone::NetdevAttrs attrsIn; attrsIn.push_back(std::make_tuple("ipv6", "ip:2001:db8::1,prefixlen:64")); c->setNetdevAttrs(ZONE_NETDEV, attrsIn); - ZoneAdmin::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); + Zone::NetdevAttrs attrsOut = c->getNetdevAttrs(ZONE_NETDEV); int gotIp = 0; for (auto& attr : attrsOut) { if (std::get<0>(attr) == "ipv6") { @@ -350,10 +425,10 @@ BOOST_AUTO_TEST_CASE(SetNetdevIpv6) BOOST_AUTO_TEST_CASE(DelNetdevIpAddress) { - auto contain = [](const ZoneAdmin::NetdevAttrs& container, const std::string& key) { + auto contain = [](const Zone::NetdevAttrs& container, const std::string& key) { return container.end() != find_if(container.begin(), container.end(), - [&](const ZoneAdmin::NetdevAttrs::value_type& value) { + [&](const Zone::NetdevAttrs::value_type& value) { return std::get<0>(value) == key; }); }; @@ -363,7 +438,7 @@ BOOST_AUTO_TEST_CASE(DelNetdevIpAddress) c->start(); ensureStarted(); c->createNetdevVeth(ZONE_NETDEV, BRIDGE_NAME); - ZoneAdmin::NetdevAttrs attrs; + Zone::NetdevAttrs attrs; attrs.push_back(std::make_tuple("ipv6", "ip:2001:db8::1,prefixlen:64")); attrs.push_back(std::make_tuple("ipv4", "ip:192.168.4.1,prefixlen:24")); c->setNetdevAttrs(ZONE_NETDEV, attrs); -- 2.7.4 From f3643dc01949f5b76180d485bf18a0e54c6c3e14 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 10 Jun 2015 18:27:02 +0200 Subject: [PATCH 15/16] Make all the API calls queue together so we guarantee order [Bug] Some API calls were async hence the sync ones could have been run before them. There was no guarantee for the calls to be ordered the way they've been requested. [Cause] N/A [Solution] Add sync calls to the same queue as the async ones so we can guarantee their order of execution. [Verification] Built, installed, run tests. Change-Id: Iab59552d46689fb86576539012004107f4e675b3 --- common/utils/worker.cpp | 17 +- common/utils/worker.hpp | 1 + server/zones-manager.cpp | 1004 ++++++++++++++++++++++++++-------------------- 3 files changed, 576 insertions(+), 446 deletions(-) diff --git a/common/utils/worker.cpp b/common/utils/worker.cpp index 7e87d33..e73c4ce 100644 --- a/common/utils/worker.cpp +++ b/common/utils/worker.cpp @@ -24,6 +24,7 @@ #include "config.hpp" #include "utils/worker.hpp" +#include "utils/latch.hpp" #include "utils/counting-map.hpp" #include "logger/logger.hpp" @@ -66,13 +67,13 @@ public: return ++mLastGroupID; } - void addTask(const Worker::Task& task, GroupID groupID) + void addTask(const Worker::Task& task, GroupID groupID, Latch* latch) { assert(task); Lock lock(mMutex); LOGT("Adding task to subgroup " << groupID); - mTaskQueue.push_back(TaskInfo{task, groupID}); + mTaskQueue.push_back(TaskInfo{task, groupID, latch}); mGroupCounter.increment(groupID); mAddedCondition.notify_one(); if (!mThread.joinable()) { @@ -97,6 +98,7 @@ private: struct TaskInfo { Worker::Task task; GroupID groupID; + Latch *latch; }; std::atomic mLastGroupID; @@ -148,6 +150,8 @@ private: try { LOGT("Executing task from subgroup " << taskInfo.groupID); taskInfo.task(); + if (taskInfo.latch) + taskInfo.latch->set(); } catch (const std::exception& e) { LOGE("Unexpected exception while executing task: " << e.what()); } @@ -177,8 +181,15 @@ Worker::Pointer Worker::createSubWorker() void Worker::addTask(const Task& task) { - mWorkerQueue->addTask(task, mGroupID); + mWorkerQueue->addTask(task, mGroupID, NULL); } +void Worker::addTaskAndWait(const Task& task) +{ + Latch latch; + + mWorkerQueue->addTask(task, mGroupID, &latch); + latch.wait(); +} } // namespace utils diff --git a/common/utils/worker.hpp b/common/utils/worker.hpp index 677f218..4733d2d 100644 --- a/common/utils/worker.hpp +++ b/common/utils/worker.hpp @@ -55,6 +55,7 @@ public: * Adds a task to the queue. */ void addTask(const Task& task); + void addTaskAndWait(const Task& task); private: typedef unsigned int GroupID; diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index a34dbe9..d213669 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -467,20 +467,24 @@ void ZonesManager::setZonesDetachOnExit() void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/) { - // get config of currently set zone and switch if switchToDefaultAfterTimeout is true - Lock lock(mMutex); + auto handler = [&, this] { + // get config of currently set zone and switch if switchToDefaultAfterTimeout is true + Lock lock(mMutex); - auto activeIter = findZone(mActiveZoneId); - auto defaultIter = findZone(mDynamicConfig.defaultId); + auto activeIter = findZone(mActiveZoneId); + auto defaultIter = findZone(mDynamicConfig.defaultId); - if (activeIter != mZones.end() && - defaultIter != mZones.end() && - get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() && - get(defaultIter).isRunning()) { + if (activeIter != mZones.end() && + defaultIter != mZones.end() && + get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() && + get(defaultIter).isRunning()) { - LOGI("Switching to default zone " << mDynamicConfig.defaultId); - focusInternal(defaultIter); - } + LOGI("Switching to default zone " << mDynamicConfig.defaultId); + focusInternal(defaultIter); + } + }; + + mWorker->addTaskAndWait(handler); } #ifdef ZONE_CONNECTION @@ -488,23 +492,27 @@ void ZonesManager::handleNotifyActiveZoneCall(const std::string& caller, const api::NotifActiveZoneIn& notif, api::MethodResultBuilder::Pointer result) { - const std::string& application = notif.first; - const std::string& message = notif.second; - LOGI("handleNotifyActiveZoneCall(" << caller << ", " << application << ", " << message - << ") called"); + auto handler = [&, this] { + const std::string& application = notif.first; + const std::string& message = notif.second; + LOGI("handleNotifyActiveZoneCall(" << caller << ", " << application << ", " << message + << ") called"); - Lock lock(mMutex); + Lock lock(mMutex); - try { - auto iter = getRunningForegroundZoneIterator(); - if (iter != mZones.end() && caller != get(iter).getId()) { - //XXX:get(iter).sendNotification(caller, application, message); + 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"); } - 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"); - } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleFileMoveCall(const std::string& srcZoneId, @@ -530,71 +538,75 @@ void ZonesManager::handleFileMoveCall(const std::string& srcZoneId, // Now when the main process has obtained FDs (by either of those methods) // it can do the copying by itself. - 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); + 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); + Lock lock(mMutex); - auto srcIter = findZone(srcZoneId); - if (srcIter == mZones.end()) { - LOGE("Source zone '" << srcZoneId << "' not found"); - return; - } - Zone& srcZone = get(srcIter); + 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 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; - } + 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 (!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 (srcZoneId == dstZoneId) { + LOGE("Cannot send a file to yourself"); + status->value = api::FILE_MOVE_WRONG_DESTINATION; + 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; - } + 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; + } - 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 (!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; + } - 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"); + 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"); + } } - } + }; + + mWorker->addTaskAndWait(handler); } #else void ZonesManager::handleNotifyActiveZoneCall(const std::string& /* caller */, @@ -623,365 +635,451 @@ void ZonesManager::handleProxyCall(const std::string& caller, GVariant* parameters, dbus::MethodResultBuilder::Pointer result) { - if (!mProxyCallPolicy->isProxyCallAllowed(caller, - target, - targetBusName, - targetObjectPath, - targetInterface, - targetMethod)) { - LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName + auto handler = [&, this] { + if (!mProxyCallPolicy->isProxyCallAllowed(caller, + target, + targetBusName, + targetObjectPath, + targetInterface, + targetMethod)) { + LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName + << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod); + result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden"); + return; + } + + LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod); - result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden"); - return; - } - LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName - << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod); + auto asyncResultCallback = [result](dbus::AsyncMethodCallResult & asyncMethodCallResult) { + try { + GVariant* targetResult = asyncMethodCallResult.get(); + result->set(g_variant_new("(v)", targetResult)); + } catch (dbus::DbusException& e) { + result->setError(api::ERROR_FORWARDED, e.what()); + } + }; - auto asyncResultCallback = [result](dbus::AsyncMethodCallResult & asyncMethodCallResult) { - try { - GVariant* targetResult = asyncMethodCallResult.get(); - result->set(g_variant_new("(v)", targetResult)); - } catch (dbus::DbusException& e) { - result->setError(api::ERROR_FORWARDED, e.what()); + if (target != HOST_ID) { + result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target"); + return; } - }; - if (target != HOST_ID) { - result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target"); - return; - } + mHostDbusConnection.proxyCallAsync(targetBusName, + targetObjectPath, + targetInterface, + targetMethod, + parameters, + asyncResultCallback); + }; - mHostDbusConnection.proxyCallAsync(targetBusName, - targetObjectPath, - targetInterface, - targetMethod, - parameters, - asyncResultCallback); + mWorker->addTaskAndWait(handler); } #endif //DBUS_CONNECTION void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result) { - Lock lock(mMutex); + auto handler = [&, this] { + LOGI("GetZoneIds call"); - auto zoneIds = std::make_shared(); - for (const auto& zone : mZones) { - zoneIds->values.push_back(zone->getId()); - } + Lock lock(mMutex); - result->set(zoneIds); + auto zoneIds = std::make_shared(); + for (const auto& zone : mZones) { + zoneIds->values.push_back(zone->getId()); + } + + result->set(zoneIds); + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result) { - LOGI("GetActiveZoneId call"); - auto zoneId = std::make_shared(); - zoneId->value = getRunningForegroundZoneId(); - result->set(zoneId); + auto handler = [&, this] { + LOGI("GetActiveZoneId call"); + + auto zoneId = std::make_shared(); + zoneId->value = getRunningForegroundZoneId(); + result->set(zoneId); + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("GetZoneInfo call"); + auto handler = [&, this] { + LOGI("GetZoneInfo call"); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(zoneId.value); - if (iter == mZones.end()) { - LOGE("No zone with id=" << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(zoneId.value); + if (iter == mZones.end()) { + LOGE("No zone with id=" << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - Zone& zone = get(iter); - auto zoneInfo = std::make_shared(); + Zone& zone = get(iter); + auto zoneInfo = std::make_shared(); + + if (zone.isRunning()) { + zoneInfo->state = "RUNNING"; + } else if (zone.isStopped()) { + zoneInfo->state = "STOPPED"; + } else if (zone.isPaused()) { + zoneInfo->state = "FROZEN"; + } else { + LOGE("Unrecognized state of zone id=" << zoneId.value); + result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone"); + return; + } - if (zone.isRunning()) { - zoneInfo->state = "RUNNING"; - } else if (zone.isStopped()) { - zoneInfo->state = "STOPPED"; - } else if (zone.isPaused()) { - zoneInfo->state = "FROZEN"; - } else { - LOGE("Unrecognized state of zone id=" << zoneId.value); - result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone"); - return; - } + zoneInfo->id = zone.getId(); + zoneInfo->vt = zone.getVT(); + zoneInfo->rootPath = zone.getRootPath(); + result->set(zoneInfo); + }; - zoneInfo->id = zone.getId(); - zoneInfo->vt = zone.getVT(); - zoneInfo->rootPath = zone.getRootPath(); - result->set(zoneInfo); + mWorker->addTaskAndWait(handler); } void ZonesManager::handleSetNetdevAttrsCall(const api::SetNetDevAttrsIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("SetNetdevAttrs call"); - try { - Lock lock(mMutex); + auto handler = [&, this] { + LOGI("SetNetdevAttrs call"); + + try { + Lock lock(mMutex); + + // TODO: Use vector instead of tuples + std::vector> attrsAsTuples; + for(const auto& entry: data.attrs){ + attrsAsTuples.push_back(std::make_tuple(entry.first, entry.second)); + } - // TODO: Use vector instead of tuples - std::vector> attrsAsTuples; - for(const auto& entry: data.attrs){ - attrsAsTuples.push_back(std::make_tuple(entry.first, entry.second)); + getZone(data.id).setNetdevAttrs(data.netDev, attrsAsTuples); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); } + }; - getZone(data.id).setNetdevAttrs(data.netDev, attrsAsTuples); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't set attributes: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("GetNetdevAttrs call"); - try { - Lock lock(mMutex); - auto netDevAttrs = std::make_shared(); - const auto attrs = getZone(data.first).getNetdevAttrs(data.second); + auto handler = [&, this] { + LOGI("GetNetdevAttrs call"); + + try { + Lock lock(mMutex); + auto netDevAttrs = std::make_shared(); + const auto attrs = getZone(data.first).getNetdevAttrs(data.second); - for (size_t i = 0; i < attrs.size(); ++i) { - netDevAttrs->values.push_back({std::get<0>(attrs[i]), std::get<1>(attrs[i])}); + for (size_t i = 0; i < attrs.size(); ++i) { + netDevAttrs->values.push_back({std::get<0>(attrs[i]), std::get<1>(attrs[i])}); + } + result->set(netDevAttrs); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.first); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); } - result->set(netDevAttrs); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.first); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't set attributes: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("GetNetdevList call"); - try { - Lock lock(mMutex); - auto netDevList = std::make_shared(); - netDevList->values = getZone(zoneId.value).getNetdevList(); - result->set(netDevList); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't set attributes: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + auto handler = [&, this] { + LOGI("GetNetdevList call"); + + try { + Lock lock(mMutex); + auto netDevList = std::make_shared(); + netDevList->values = getZone(zoneId.value).getNetdevList(); + result->set(netDevList); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't set attributes: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("CreateNetdevVeth call"); - try { - Lock lock(mMutex); + auto handler = [&, this] { + LOGI("CreateNetdevVeth call"); - getZone(data.id).createNetdevVeth(data.zoneDev, data.hostDev); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't create veth: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + try { + Lock lock(mMutex); + + getZone(data.id).createNetdevVeth(data.zoneDev, data.hostDev); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't create veth: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("CreateNetdevMacvlan call"); - try { - Lock lock(mMutex); - getZone(data.id).createNetdevMacvlan(data.zoneDev, data.hostDev, data.mode); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't create macvlan: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + auto handler = [&, this] { + LOGI("CreateNetdevMacvlan call"); + + try { + Lock lock(mMutex); + getZone(data.id).createNetdevMacvlan(data.zoneDev, data.hostDev, data.mode); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't create macvlan: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("CreateNetdevPhys call"); - try { - Lock lock(mMutex); + auto handler = [&, this] { + LOGI("CreateNetdevPhys call"); - getZone(data.first).moveNetdev(data.second); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.first); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't create netdev: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + try { + Lock lock(mMutex); + + getZone(data.first).moveNetdev(data.second); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.first); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't create netdev: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("DestroyNetdev call"); - try { - Lock lock(mMutex); + auto handler = [&, this] { + LOGI("DestroyNetdev call"); - getZone(data.first).destroyNetdev(data.second); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.first); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't create netdev: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + try { + Lock lock(mMutex); + + getZone(data.first).destroyNetdev(data.second); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.first); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't create netdev: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("DelNetdevIpAddress call"); - try { - Lock lock(mMutex); - getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.zone); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE("Can't delete address: " << ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + auto handler = [&, this] { + LOGI("DelNetdevIpAddress call"); + + try { + Lock lock(mMutex); + getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE("Can't delete address: " << ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("DeclareFile call"); + auto handler = [&, this] { + LOGI("DeclareFile call"); - try { - Lock lock(mMutex); - auto declaration = std::make_shared(); - declaration->value = getZone(data.zone).declareFile(data.type, data.path, data.flags, data.mode); - result->set(declaration); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.zone); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const config::ConfigException& ex) { - LOGE("Can't declare file: " << ex.what()); - result->setError(api::ERROR_INTERNAL, "Internal error"); - } + try { + Lock lock(mMutex); + auto declaration = std::make_shared(); + declaration->value = getZone(data.zone).declareFile(data.type, data.path, data.flags, data.mode); + result->set(declaration); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const config::ConfigException& ex) { + LOGE("Can't declare file: " << ex.what()); + result->setError(api::ERROR_INTERNAL, "Internal error"); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("DeclareMount call"); + auto handler = [&, this] { + LOGI("DeclareMount call"); - try { - Lock lock(mMutex); - auto declaration = std::make_shared(); - declaration->value = getZone(data.zone).declareMount(data.source, data.target, data.type, data.flags, data.data); - result->set(declaration); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.zone); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const config::ConfigException& ex) { - LOGE("Can't declare mount: " << ex.what()); - result->setError(api::ERROR_INTERNAL, "Internal error"); - } + try { + Lock lock(mMutex); + auto declaration = std::make_shared(); + declaration->value = getZone(data.zone).declareMount(data.source, data.target, data.type, data.flags, data.data); + result->set(declaration); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const config::ConfigException& ex) { + LOGE("Can't declare mount: " << ex.what()); + result->setError(api::ERROR_INTERNAL, "Internal error"); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("DeclareLink call"); - try { - Lock lock(mMutex); - auto declaration = std::make_shared(); - declaration->value = getZone(data.zone).declareLink(data.source, data.target); - result->set(declaration); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.zone); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const config::ConfigException& ex) { - LOGE("Can't declare link: " << ex.what()); - result->setError(api::ERROR_INTERNAL, "Internal error"); - } + auto handler = [&, this] { + LOGI("DeclareLink call"); + + try { + Lock lock(mMutex); + auto declaration = std::make_shared(); + declaration->value = getZone(data.zone).declareLink(data.source, data.target); + result->set(declaration); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.zone); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const config::ConfigException& ex) { + LOGE("Can't declare link: " << ex.what()); + result->setError(api::ERROR_INTERNAL, "Internal error"); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("GetDeclarations call Id=" << zoneId.value); - try { - Lock lock(mMutex); - auto declarations = std::make_shared(); - declarations->values = getZone(zoneId.value).getDeclarations(); - result->set(declarations); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE(ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + auto handler = [&, this] { + LOGI("GetDeclarations call Id=" << zoneId.value); + + try { + Lock lock(mMutex); + auto declarations = std::make_shared(); + declarations->values = getZone(zoneId.value).getDeclarations(); + result->set(declarations); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE(ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("RemoveDeclaration call Id=" << data.first); - try { - Lock lock(mMutex); - getZone(data.first).removeDeclaration(data.second); - result->setVoid(); - } catch (const InvalidZoneIdException&) { - LOGE("No zone with id=" << data.first); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - } catch (const std::runtime_error& ex) { - LOGE(ex.what()); - result->setError(api::ERROR_INTERNAL, ex.what()); - } + auto handler = [&, this] { + LOGI("RemoveDeclaration call Id=" << data.first); + + try { + Lock lock(mMutex); + getZone(data.first).removeDeclaration(data.second); + result->setVoid(); + } catch (const InvalidZoneIdException&) { + LOGE("No zone with id=" << data.first); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + } catch (const std::runtime_error& ex) { + LOGE(ex.what()); + result->setError(api::ERROR_INTERNAL, ex.what()); + } + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("SetActiveZone call; Id=" << zoneId.value ); + auto handler = [&, this] { + LOGI("SetActiveZone call; Id=" << zoneId.value ); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(zoneId.value); - if (iter == mZones.end()) { - LOGE("No zone with id=" << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(zoneId.value); + if (iter == mZones.end()) { + LOGE("No zone with id=" << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - if (!get(iter).isRunning()) { - LOGE("Could not activate stopped or paused zone"); - result->setError(api::ERROR_ZONE_NOT_RUNNING, - "Could not activate stopped or paused zone"); - return; - } + if (!get(iter).isRunning()) { + LOGE("Could not activate stopped or paused zone"); + result->setError(api::ERROR_ZONE_NOT_RUNNING, + "Could not activate stopped or paused zone"); + return; + } - focusInternal(iter); - result->setVoid(); + focusInternal(iter); + result->setVoid(); + }; + + mWorker->addTaskAndWait(handler); } @@ -1116,20 +1214,24 @@ void ZonesManager::createZone(const std::string& id, void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data, api::MethodResultBuilder::Pointer result) { - try { - createZone(data.first, data.second); - result->setVoid(); - } catch (const InvalidZoneIdException& e) { - result->setError(api::ERROR_INVALID_ID, "Existing or invalid zone id"); - } catch (const std::runtime_error& e) { - result->setError(api::ERROR_INTERNAL, "Failed to create zone"); - } + auto creator = [&, this] { + try { + createZone(data.first, data.second); + result->setVoid(); + } catch (const InvalidZoneIdException& e) { + result->setError(api::ERROR_INVALID_ID, "Existing or invalid zone id"); + } catch (const std::runtime_error& e) { + result->setError(api::ERROR_INTERNAL, "Failed to create zone"); + } + }; + + mWorker->addTaskAndWait(creator); } void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - auto destroyer = [zoneId, result, this] { + auto destroyer = [=] { try { LOGI("Destroying zone " << zoneId.value); destroyZone(zoneId.value); @@ -1150,9 +1252,9 @@ void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId, void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("ShutdownZone call; Id=" << zoneId.value); + auto shutdown = [=] { + LOGI("ShutdownZone call; Id=" << zoneId.value); - auto shutdown = [zoneId, result, this] { try { LOGT("Shutdown zone " << zoneId.value); @@ -1179,9 +1281,9 @@ void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId, void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("StartZone call; Id=" << zoneId.value); + auto startAsync = [=] { + LOGI("StartZone call; Id=" << zoneId.value); - auto startAsync = [this, zoneId, result]() { try { LOGT("Start zone " << zoneId.value); @@ -1206,145 +1308,161 @@ void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId, void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("LockZone call; Id=" << zoneId.value ); + auto handler = [&, this] { + LOGI("LockZone call; Id=" << zoneId.value ); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(zoneId.value); - if (iter == mZones.end()) { - LOGE("Failed to lock zone - no such zone id: " << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(zoneId.value); + if (iter == mZones.end()) { + LOGE("Failed to lock zone - no such zone id: " << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - Zone& zone = get(iter); - if (!zone.isRunning()) { - LOGE("Zone id=" << zoneId.value << " is not running."); - result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); - return; - } + Zone& zone = get(iter); + if (!zone.isRunning()) { + LOGE("Zone id=" << zoneId.value << " is not running."); + result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); + return; + } - LOGT("Lock zone"); - try { - zone.goBackground();// make sure it will be in background after unlock - zone.suspend(); - refocus(); - } catch (ZoneOperationException& e) { - LOGE(e.what()); - result->setError(api::ERROR_INTERNAL, e.what()); - return; - } + LOGT("Lock zone"); + try { + zone.goBackground();// make sure it will be in background after unlock + zone.suspend(); + refocus(); + } catch (ZoneOperationException& e) { + LOGE(e.what()); + result->setError(api::ERROR_INTERNAL, e.what()); + return; + } - result->setVoid(); + result->setVoid(); + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId, api::MethodResultBuilder::Pointer result) { - LOGI("UnlockZone call; Id=" << zoneId.value ); + auto handler = [&, this] { + LOGI("UnlockZone call; Id=" << zoneId.value ); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(zoneId.value); - if (iter == mZones.end()) { - LOGE("Failed to unlock zone - no such zone id: " << zoneId.value); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(zoneId.value); + if (iter == mZones.end()) { + LOGE("Failed to unlock zone - no such zone id: " << zoneId.value); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - Zone& zone = get(iter); - if (!zone.isPaused()) { - LOGE("Zone id=" << zoneId.value << " is not paused."); - result->setError(api::ERROR_INVALID_STATE, "Zone is not paused"); - return; - } + Zone& zone = get(iter); + if (!zone.isPaused()) { + LOGE("Zone id=" << zoneId.value << " is not paused."); + result->setError(api::ERROR_INVALID_STATE, "Zone is not paused"); + return; + } - LOGT("Unlock zone"); - try { - zone.resume(); - } catch (ZoneOperationException& e) { - LOGE(e.what()); - result->setError(api::ERROR_INTERNAL, e.what()); - return; - } + LOGT("Unlock zone"); + try { + zone.resume(); + } catch (ZoneOperationException& e) { + LOGE(e.what()); + result->setError(api::ERROR_INTERNAL, e.what()); + return; + } - result->setVoid(); + result->setVoid(); + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("GrantDevice call; id=" << data.id << "; dev=" << data.device); + auto handler = [&, this] { + LOGI("GrantDevice call; id=" << data.id << "; dev=" << data.device); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(data.id); - if (iter == mZones.end()) { - LOGE("Failed to grant device - no such zone id: " << data.id); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(data.id); + if (iter == mZones.end()) { + LOGE("Failed to grant device - no such zone id: " << data.id); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - Zone& zone = get(iter); - if (!zone.isRunning() && !zone.isPaused()) { - LOGE("Zone id=" << data.id << " is not running"); - result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); - return; - } + Zone& zone = get(iter); + if (!zone.isRunning() && !zone.isPaused()) { + LOGE("Zone id=" << data.id << " is not running"); + result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); + return; + } - std::string devicePath = "/dev/" + data.device; + std::string devicePath = "/dev/" + data.device; - if (!lxc::isDevice(devicePath)) { - LOGE("Failed to grant device - cannot acces device: " << data.device); - result->setError(api::ERROR_FORBIDDEN, "Cannot access device"); - return; - } + if (!lxc::isDevice(devicePath)) { + LOGE("Failed to grant device - cannot acces device: " << data.device); + result->setError(api::ERROR_FORBIDDEN, "Cannot access device"); + return; + } - // assume device node is created inside zone - if (!lxc::setDeviceAccess(data.id, devicePath, true, data.flags)) { - LOGE("Failed to grant device: " << data.device << " for zone: " << data.id); - result->setError(api::ERROR_INTERNAL, "Cannot grant device"); - return; - } + // assume device node is created inside zone + if (!lxc::setDeviceAccess(data.id, devicePath, true, data.flags)) { + LOGE("Failed to grant device: " << data.device << " for zone: " << data.id); + result->setError(api::ERROR_INTERNAL, "Cannot grant device"); + return; + } - result->setVoid(); + result->setVoid(); + }; + + mWorker->addTaskAndWait(handler); } void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data, api::MethodResultBuilder::Pointer result) { - LOGI("RevokeDevice call; id=" << data.first << "; dev=" << data.second); + auto handler = [&, this] { + LOGI("RevokeDevice call; id=" << data.first << "; dev=" << data.second); - Lock lock(mMutex); + Lock lock(mMutex); - auto iter = findZone(data.first); - if (iter == mZones.end()) { - LOGE("Failed to revoke device - no such zone id: " << data.first); - result->setError(api::ERROR_INVALID_ID, "No such zone id"); - return; - } + auto iter = findZone(data.first); + if (iter == mZones.end()) { + LOGE("Failed to revoke device - no such zone id: " << data.first); + result->setError(api::ERROR_INVALID_ID, "No such zone id"); + return; + } - Zone& zone = get(iter); - if (!zone.isRunning() && !zone.isPaused()) { - LOGE("Zone id=" << data.first << " is not running"); - result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); - return; - } - std::string devicePath = "/dev/" + data.second; + Zone& zone = get(iter); + if (!zone.isRunning() && !zone.isPaused()) { + LOGE("Zone id=" << data.first << " is not running"); + result->setError(api::ERROR_INVALID_STATE, "Zone is not running"); + return; + } + std::string devicePath = "/dev/" + data.second; - if (!lxc::isDevice(devicePath)) { - LOGE("Failed to revoke device - cannot acces device: " << data.second); - result->setError(api::ERROR_FORBIDDEN, "Cannot access device"); - return; - } + if (!lxc::isDevice(devicePath)) { + LOGE("Failed to revoke device - cannot acces device: " << data.second); + result->setError(api::ERROR_FORBIDDEN, "Cannot access device"); + return; + } - if (!lxc::setDeviceAccess(data.first, devicePath, false, 0)) { - LOGE("Failed to revoke device: " << data.second << " for zone: " << data.first); - result->setError(api::ERROR_INTERNAL, "Cannot revoke device"); - return; - } + if (!lxc::setDeviceAccess(data.first, devicePath, false, 0)) { + LOGE("Failed to revoke device: " << data.second << " for zone: " << data.first); + result->setError(api::ERROR_INTERNAL, "Cannot revoke device"); + return; + } + + result->setVoid(); + }; - result->setVoid(); + mWorker->addTaskAndWait(handler); } } // namespace vasum -- 2.7.4 From aca7e2907ed4461fad8a49d4d4461e43ecdc1837 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Wed, 3 Jun 2015 14:45:26 +0200 Subject: [PATCH 16/16] Check vasum runtime environment, provide utility to check kernel config [Bug/Feature] check vasum enviroment and kernel config [Cause] N/A [Solution] server option to check runtime, script based on lxc-checkconfig [Verification] Build, install on target, run server and script Change-Id: I28b6982694e7918cad31e59cee35b5872e554246 --- packaging/vasum.spec | 1 + server/CMakeLists.txt | 2 + server/main.cpp | 4 ++ server/scripts/vasum-check-env.sh | 84 +++++++++++++++++++++++++++++++++++++++ server/server.cpp | 75 ++++++++++++++++++++++++++++++++++ server/server.hpp | 5 +++ 6 files changed, 171 insertions(+) create mode 100755 server/scripts/vasum-check-env.sh diff --git a/packaging/vasum.spec b/packaging/vasum.spec index bd7346c..38c7cf6 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -44,6 +44,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 %dir /etc/vasum %dir /etc/vasum/templates %config /etc/vasum/daemon.conf diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 92672c1..d5104db 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -55,3 +55,5 @@ 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) diff --git a/server/main.cpp b/server/main.cpp index fb3eed4..55a795e 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -69,6 +69,7 @@ int main(int argc, char* argv[]) ("root,r", "Don't drop root privileges at startup") ("version,v", "show application version") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") + ("check,c", "check runtime environment and exit") ; po::variables_map vm; @@ -100,6 +101,9 @@ int main(int argc, char* argv[]) } else if (vm.count("version")) { std::cout << PROGRAM_NAME_AND_VERSION << std::endl; return 0; + } else if (vm.count("check")) { + std::cout << "Checking runtime environment..." << std::endl; + return Server::checkEnvironment() ? 0 : 1; } Logger::setLogLevel(vm["log-level"].as()); diff --git a/server/scripts/vasum-check-env.sh b/server/scripts/vasum-check-env.sh new file mode 100755 index 0000000..a03524c --- /dev/null +++ b/server/scripts/vasum-check-env.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +# Note: based on lxc-checkconfig script + +: ${CONFIG:=/proc/config.gz} +: ${GREP:=zgrep} + +SETCOLOR_SUCCESS="printf \\033[1;32m" +SETCOLOR_FAILURE="printf \\033[1;31m" +SETCOLOR_WARNING="printf \\033[1;33m" +SETCOLOR_NORMAL="printf \\033[0;39m" + +FAILURE=false + +is_builtin() { + $GREP -q "$1=y" $CONFIG + return $? +} + +# is_enabled has two parameters +# 1=kernel option +# 2=is the option mandatory (optional parameter) +is_enabled() { + mandatory=$2 + is_builtin $1 + RES=$? + if [ $RES -eq 0 ]; then + $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL + else + if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then + FAILURE=true + $SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL + else + $SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL + fi + fi +} + + +if [ ! -f $CONFIG ]; then + echo "no $CONFIG, searching..." + CONFIG="/boot/config-$(uname -r)" + if [ ! -f $CONFIG ]; then + echo "kernel config not found"; exit 1; + fi +fi + +echo "kernel config: $CONFIG" +KVER=$($GREP '^# Linux.*Kernel Configuration' $CONFIG | sed -r 's/#.* ([0-9]+\.[0-9]+\.[0-9]+).*/\1/') + +KVER_MAJOR=$(echo $KVER | sed -r 's/([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/') +if [ "$KVER_MAJOR" = "2" ]; then + KVER_MINOR=$(echo $KVER | sed -r 's/2.6.([0-9]{2}).*/\1/') +else + KVER_MINOR=$(echo $KVER | sed -r 's/[0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/') +fi + +echo "kver=$KVER, major.minor=$KVER_MAJOR.$KVER_MINOR" + +echo "--- Namespaces ---" +echo -n "Namespaces: " && is_enabled CONFIG_NAMESPACES yes +echo -n "Utsname namespace: " && is_enabled CONFIG_UTS_NS yes +echo -n "Ipc namespace: " && is_enabled CONFIG_IPC_NS yes +echo -n "Pid namespace: " && is_enabled CONFIG_PID_NS yes +echo -n "User namespace: " && is_enabled CONFIG_USER_NS yes +echo -n "Network namespace: " && is_enabled CONFIG_NET_NS yes +echo -n "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES yes +echo +echo "--- Network virtualization ---" +echo -n "VETH: " && is_enabled CONFIG_VETH yes +echo -n "VLAN: " && is_enabled CONFIG_VLAN_8021Q yes +echo -n "MACVLAN: " && is_enabled CONFIG_MACVLAN yes +echo +echo "--- Control groups ---" +echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes +echo -n "PID cpuset: " && is_enabled CONFIG_PROC_PID_CPUSET yes +echo +echo -n "CFS Bandwidth: " && is_enabled CONFIG_CFS_BANDWIDTH yes + +if $FAILURE; then + exit 1 +else + exit 0 +fi diff --git a/server/server.cpp b/server/server.cpp index 936db28..befb8da 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -36,6 +36,7 @@ #include "utils/signal.hpp" #include "utils/exception.hpp" +#include #include #include #include @@ -47,6 +48,13 @@ #include #include +#include +#include +#include +#include +#include +#include + #ifndef VASUM_USER #error "VASUM_USER must be defined!" @@ -143,6 +151,73 @@ void Server::terminate() gSignalLatch.set(); } +bool Server::checkEnvironment() +{ + // check kernel + struct utsname u; + int version, major, minor; + ::uname(&u); + version = major = minor = 0; + ::sscanf(u.release, "%d.%d.%d", &version, &major, &minor); + if (version < 2 || (version == 2 && major < 6) || (version == 2 && major == 6 && minor < 29)) { + // 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; + return false; + } + else + std::cout << "kernel " << u.release << " [OK]" << std::endl; + + // check lxc (TODO check if running on broken ABI version) + if (::strcmp(lxc_get_version(), LXC_VERSION)!=0) { + // versions that matters: + // 1.1.0 added function ptr 'in-the-middle' destroy_with_snapshots, snapshot_destroy_all (breaks ABI) + // 1.1.2 added function ptr 'append' attach_interface,detach_interface,checkpoint,restore (safe for ABI) + std::cout << "LXC version not match, compiled for " << LXC_VERSION << ", installed " << lxc_get_version() << std::endl; + return false; + } + else + std::cout << "LXC version " << lxc_get_version() << " [OK]" << std::endl; + + // check cgroups (and its subsystems?) + 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; + return false; + } + + bool err = false; + std::vector cgroupSubsCheck = {"cpu", "cpuset", "memory"}; + for (std::string f : cgroupSubsCheck) { + if (::faccessat(fd, f.c_str(), R_OK|X_OK, 0) == -1) { + std::cout << "no cgroups support (can't access " << cgroupCheck << "/" << f << ")" << std::endl; + err=true; + } + } + ::close(fd); + if (err) { + std::cout << "cgroups problem, run vasum-check-env" << std::endl; + return false; + } + else + std::cout << "cgroups support " << " [OK]" << std::endl; + + // 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; + return false; + } + else + std::cout << "namespaces support " << " [OK]" << std::endl; + ::close(fd); + + return true; +} + + bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) { namespace fs = boost::filesystem; diff --git a/server/server.hpp b/server/server.hpp index 8bac0b0..e034e0f 100644 --- a/server/server.hpp +++ b/server/server.hpp @@ -54,6 +54,11 @@ public: */ void terminate(); + /** + * Check server runtime environment + */ + static bool checkEnvironment(); + private: std::string mConfigPath; -- 2.7.4