Add PluginManager 45/27845/13
authorZofia Abramowska <z.abramowska@samsung.com>
Fri, 19 Sep 2014 14:42:02 +0000 (16:42 +0200)
committerLukasz Wojciechowski <l.wojciechow@partner.samsung.com>
Thu, 16 Oct 2014 11:11:10 +0000 (04:11 -0700)
Add cynara service manager for loading and managing dynamic loaded
plugins supporting custom policy types.

Change-Id: I94c3bfa4842a6a8d0a078ac910aba5e54db7b468

src/service/CMakeLists.txt
src/service/logic/Logic.cpp
src/service/logic/Logic.h
src/service/main/Cynara.cpp
src/service/main/Cynara.h
src/service/main/pointers.h
src/service/plugin/PluginManager.cpp [new file with mode: 0644]
src/service/plugin/PluginManager.h [new file with mode: 0644]

index f1c4c8a..f8d2eb8 100644 (file)
@@ -22,6 +22,7 @@ SET(CYNARA_SOURCES
     ${CYNARA_SERVICE_PATH}/logic/Logic.cpp
     ${CYNARA_SERVICE_PATH}/main/Cynara.cpp
     ${CYNARA_SERVICE_PATH}/main/main.cpp
+    ${CYNARA_SERVICE_PATH}/plugin/PluginManager.cpp
     ${CYNARA_SERVICE_PATH}/sockets/Descriptor.cpp
     ${CYNARA_SERVICE_PATH}/sockets/SocketManager.cpp
     )
@@ -29,6 +30,7 @@ SET(CYNARA_SOURCES
 INCLUDE_DIRECTORIES(
     ${CYNARA_SERVICE_PATH}
     ${CYNARA_PATH}
+    ${CYNARA_PATH}/include
     )
 
 ADD_EXECUTABLE(${TARGET_CYNARA} ${CYNARA_SOURCES})
@@ -37,6 +39,7 @@ TARGET_LINK_LIBRARIES(${TARGET_CYNARA}
     ${CYNARA_DEP_LIBRARIES}
     ${TARGET_CYNARA_COMMON}
     ${TARGET_LIB_CYNARA_STORAGE}
+    dl
     )
 
 INSTALL(TARGETS ${TARGET_CYNARA} DESTINATION ${BIN_INSTALL_DIR})
index d05f512..60a0cce 100644 (file)
@@ -97,13 +97,29 @@ bool Logic::check(RequestContextPtr context UNUSED, const PolicyKey &key,
             LOGD("check of policy key <%s> returned DENY", key.toString().c_str());
             return true;
     }
-    //todo pass question to proper plugin that:
-    //  1) returns false when answer has to be waited for (UI)
-    //  2) returns true if Response is to be generated
-    // In case 1) context should be saved in plugin in order to return answer when ready.
 
-    //in case no proper plugin is found
-    throw PluginNotFoundException(result);
+    ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType());
+    if (!plugin) {
+        throw PluginNotFoundException(result);
+    }
+
+    AgentType requiredAgent;
+    PluginData pluginData;
+
+    auto ret = plugin->check(key.client().toString(), key.user().toString(),
+                             key.privilege().toString(), result, requiredAgent, pluginData);
+
+    switch (ret) {
+        case ExternalPluginInterface::PluginStatus::ANSWER_READY:
+            return true;
+        case ExternalPluginInterface::PluginStatus::ANSWER_NOTREADY:
+            //todo send request to agent
+            //context should be saved in plugin in order to return answer when ready
+            return false;
+        default:
+            //todo make additional class
+            throw std::runtime_error("Plugin error");
+    }
 }
 
 void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) {
index 28fdeea..3c434a5 100644 (file)
@@ -27,6 +27,7 @@
 #include <types/PolicyResult.h>
 
 #include <main/pointers.h>
+#include <plugin/PluginManager.h>
 #include <request/pointers.h>
 #include <request/RequestTaker.h>
 
@@ -37,6 +38,10 @@ public:
     Logic();
     virtual ~Logic();
 
+    void bindPluginManager(PluginManagerPtr pluginManager) {
+        m_pluginManager = pluginManager;
+    }
+
     void bindStorage(StoragePtr storage) {
         m_storage = storage;
     }
@@ -46,6 +51,7 @@ public:
     }
 
     void unbindAll(void) {
+        m_pluginManager.reset();
         m_storage.reset();
         m_socketManager.reset();
     }
@@ -59,6 +65,7 @@ public:
     virtual void execute(RequestContextPtr context, SignalRequestPtr request);
 
 private:
+    PluginManagerPtr m_pluginManager;
     StoragePtr m_storage;
     SocketManagerPtr m_socketManager;
 
index 4a4deb4..1a0d45e 100644 (file)
@@ -27,6 +27,7 @@
 #include <exceptions/InitException.h>
 
 #include <logic/Logic.h>
+#include <plugin/PluginManager.h>
 #include <sockets/SocketManager.h>
 #include <storage/InMemoryStorageBackend.h>
 #include <storage/Storage.h>
@@ -58,12 +59,27 @@ const std::string Cynara::storageDir(void) {
     return dir;
 }
 
+const std::string Cynara::pluginDir(void) {
+    std::string dir("/usr/lib/cynara/");
+
+#ifdef CYNARA_LIB_PATH
+    dir = CYNARA_LIB_PATH;
+#else
+    LOGW("Cynara compiled without CYNARA_LIB_PATH flag. Using default plugin directory.");
+#endif
+    dir += "plugin/";
+    LOGI("Cynara plugin path <%s>", dir.c_str());
+    return dir;
+}
+
 void Cynara::init(void) {
     m_logic = std::make_shared<Logic>();
+    m_pluginManager = std::make_shared<PluginManager>(pluginDir());
     m_socketManager = std::make_shared<SocketManager>();
     m_storageBackend = std::make_shared<InMemoryStorageBackend>(storageDir());
     m_storage = std::make_shared<Storage>(*m_storageBackend);
 
+    m_logic->bindPluginManager(m_pluginManager);
     m_logic->bindStorage(m_storage);
     m_logic->bindSocketManager(m_socketManager);
 
@@ -90,6 +106,7 @@ void Cynara::finalize(void) {
     }
 
     m_logic.reset();
+    m_pluginManager.reset();
     m_socketManager.reset();
     m_storageBackend.reset();
     m_storage.reset();
index ecdde62..e89eda3 100644 (file)
@@ -30,10 +30,12 @@ namespace Cynara {
 class Cynara {
 private:
     LogicPtr m_logic;
+    PluginManagerPtr m_pluginManager;
     SocketManagerPtr m_socketManager;
     StoragePtr m_storage;
     StorageBackendPtr m_storageBackend;
 
+    static const std::string pluginDir(void);
     static const std::string storageDir(void);
 
 public:
index 652dba3..e31eeb8 100644 (file)
@@ -30,6 +30,9 @@ namespace Cynara {
 class Logic;
 typedef std::shared_ptr<Logic> LogicPtr;
 
+class PluginManager;
+typedef std::shared_ptr<PluginManager> PluginManagerPtr;
+
 class SocketManager;
 typedef std::shared_ptr<SocketManager> SocketManagerPtr;
 
diff --git a/src/service/plugin/PluginManager.cpp b/src/service/plugin/PluginManager.cpp
new file mode 100644 (file)
index 0000000..3d21b49
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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        src/service/plugin/PluginManager.cpp
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @version     1.0
+ * @brief       Definition of PluginManager class
+ */
+
+#define _BSD_SOURCE_
+
+#include <cinttypes>
+#include <cstdlib>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <functional>
+
+#include <log/log.h>
+
+#include "PluginManager.h"
+
+
+namespace {
+    int pluginFilter(const struct dirent *ent) {
+#ifdef _DIRENT_HAVE_D_TYPE
+        if (ent->d_type != DT_REG) {
+            return 0;
+        }
+#endif
+        if (ent->d_name[0] == '.') {
+            return 0;
+        }
+        return 1;
+    }
+}
+
+namespace Cynara {
+
+PluginManager::PluginManager(const std::string &pluginDir) : m_dir(pluginDir) {
+    loadPlugins();
+}
+
+ExternalPluginPtr PluginManager::getPlugin(PolicyType pType) {
+    return m_plugins[pType];
+}
+
+void PluginManager::loadPlugins(void) {
+    struct dirent **nameList = NULL;
+    int fileAmount = scandir(m_dir.c_str(), &nameList, pluginFilter, alphasort);
+
+    if (fileAmount < 0) {
+        auto error = strerror(errno);
+        LOGE("Couldn't scan for plugins in <%s> : <%s>", m_dir.c_str(), error);
+        return;
+    }
+
+    std::unique_ptr<dirent*, std::function<void(dirent**)>> direntPtr(nameList,
+            [fileAmount](dirent** dirs) {
+                for (int i = 0; i < fileAmount; i++) {
+                    free(dirs[i]);
+                }
+                free(dirs);
+            });
+    for (int i = 0; i < fileAmount; i++) {
+        openPlugin(m_dir + nameList[i]->d_name);
+    }
+}
+
+void PluginManager::openPlugin(const std::string &path) {
+    void *handle = dlopen(path.c_str(), RTLD_LAZY);
+
+    if (!handle) {
+        LOGW("File could not be dlopened <%s> : <%s>", path.c_str(), dlerror());
+        return;
+    }
+    PluginLibPtr handlePtr(handle, std::ptr_fun(dlclose));
+
+    //Flush any previous errors
+    dlerror();
+    createPlugin func = reinterpret_cast<createPlugin>(dlsym(handle, "create"));
+
+    char *error;
+    if ((error = dlerror()) != NULL) {
+        LOGE("Couldn't resolve symbol <create> from lib <%s> : <%s>", path.c_str(), error);
+        return;
+    }
+
+    ExternalPluginPtr pluginPtr(func());
+
+    if (!pluginPtr) {
+        LOGE("Couldn't create plugin for <%s>", path.c_str());
+        return;
+    }
+
+    PolicyTypes policies = pluginPtr->getSupportedPolicyTypes();
+    if (policies.empty()) {
+        LOGE("Plugin <%s> does not support any type!", path.c_str());
+        return;
+    }
+    for (auto type : policies) {
+        if (!m_plugins.insert(std::make_pair(type, pluginPtr)).second) {
+            LOGW("policyType [%" PRIu16 "] was already supported.", type);
+        }
+    }
+
+    m_pluginLibs.push_back(std::move(handlePtr));
+}
+
+} // namespace Cynara
+
diff --git a/src/service/plugin/PluginManager.h b/src/service/plugin/PluginManager.h
new file mode 100644 (file)
index 0000000..6338cad
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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        src/service/plugin/PluginManager.h
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @version     1.0
+ * @brief       Declaration of PluginManager class
+ */
+
+#ifndef SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_
+#define SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <cynara-plugin.h>
+
+namespace Cynara {
+typedef std::shared_ptr<ExternalPluginInterface> ExternalPluginPtr;
+
+class PluginManager {
+public:
+    PluginManager(const std::string &pluginDir);
+    ExternalPluginPtr getPlugin(PolicyType pType);
+    ~PluginManager() {}
+
+private:
+    typedef std::unique_ptr<void, std::function<void (void*)>> PluginLibPtr;
+    typedef std::list<PluginLibPtr> PluginLibs;
+
+    std::string m_dir;
+    std::map<PolicyType, ExternalPluginPtr> m_plugins;
+    PluginLibs m_pluginLibs;
+
+    void loadPlugins(void);
+    void openPlugin(const std::string &path);
+};
+
+} // namespace Cynara
+#endif /* SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_ */