Add Timer for on-demand service
authorSangwan Kwon <sangwan.kwon@samsung.com>
Mon, 30 Dec 2019 04:47:43 +0000 (13:47 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Fri, 3 Jan 2020 07:58:41 +0000 (16:58 +0900)
- Timer::ExecOnce(task, predicate, 1);
Check every 1 second until predicate() returns true and
execute task() once when predicates() returns true.

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
packaging/vist.spec
src/vist/common/tests/timer.cpp [new file with mode: 0644]
src/vist/rmi/gateway.cpp
src/vist/rmi/gateway.hpp
src/vist/service/vistd.cpp
src/vist/timer.hpp [new file with mode: 0644]
src/vist/transport/protocol.cpp
src/vist/transport/protocol.hpp
src/vist/transport/server.hpp
src/vist/transport/tests/protocol.cpp
systemd/vist.socket

index b7f86b277cb131ec39fdbc9ba28bc8b1054dc682..247bc986ae48fe7b54e65f250b08566980181b2f 100644 (file)
@@ -95,13 +95,13 @@ rm -f %{vist_db_dir}/.%{name}.db*
 
 systemctl daemon-reload
 if [ $1 = 1 ]; then
-       systemctl start %{name}
+       systemctl start %{name}.socket
 elif [ $1 = 2 ]; then
-       systemctl restart %{name}
+       systemctl stop %{name}.socket
+       systemctl stop %{name}.service
+       systemctl restart %{name}.socket
 fi
 
-systemctl start %{name}
-
 %files
 %manifest %{name}.manifest
 %license LICENSE-Apache-2.0
@@ -127,10 +127,6 @@ Requires: gtest
 %description test 
 Provides internal testcases for ViST implementation.
 
-%post test
-systemctl stop %{name}.socket
-systemctl restart %{name}.service
-
 %files test
 %{_bindir}/osquery-test
 %{_bindir}/vist-test
@@ -154,7 +150,8 @@ Requires: klay
 Provides plugins for controlling policies.
 
 %pre plugins
-rm -f %{vist_plugin_dir}/*
+rm -f %{vist_plugin_dir}/bluetooth
+rm -f %{vist_plugin_dir}/wifi
 
 %files plugins
 %manifest packaging/%{name}-plugins.manifest
diff --git a/src/vist/common/tests/timer.cpp b/src/vist/common/tests/timer.cpp
new file mode 100644 (file)
index 0000000..7a120cb
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2019 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
+ */
+
+#include <gtest/gtest.h>
+
+#include <vist/timer.hpp>
+
+#include <string>
+
+using namespace vist;
+
+TEST(TimerTests, exec_once)
+{
+       int count = 0;
+
+       auto task = [&count]() {
+               count++;
+       };
+
+       auto predicate = []() -> bool {
+               return true;
+       };
+
+       /// Check every 1 second until predicate() returns true and
+       /// execute task() once when predicates() returns true.
+       Timer::ExecOnce(task, predicate, 1);
+
+       std::this_thread::sleep_for(std::chrono::seconds(2));
+       EXPECT_EQ(count, 1);
+}
index d8c176004cefb614a9c77254450d128ffa894e14..7654d1c030f255cd1b2fc112e9102d6384a903d3 100644 (file)
@@ -57,9 +57,9 @@ public:
                this->server = std::make_unique<Server>(path, dispatcher);
        }
 
-       inline void start()
+       inline void start(unsigned int timeout, Timer::Predicate condition)
        {
-               this->server->run();
+               this->server->run(timeout, condition);
        }
 
        inline void stop()
@@ -77,9 +77,9 @@ Gateway::Gateway(const std::string& path) : pImpl(std::make_unique<Impl>(*this,
 
 Gateway::~Gateway() = default;
 
-void Gateway::start(void)
+void Gateway::start(unsigned int timeout, Timer::Predicate condition)
 {
-       this->pImpl->start();
+       this->pImpl->start(timeout, condition);
 }
 
 void Gateway::stop(void)
index 4a836198c7c474e2e44637bc0dfd922ae072b93b..e1195d907e1cb5f86e52a70f8391232deecad48c 100644 (file)
@@ -25,6 +25,7 @@
 #define EXPOSE(gateway, object, function) gateway.expose(object, #function, function)
 
 #include <vist/klass/functor.hpp>
+#include <vist/timer.hpp>
 
 #include <memory>
 #include <string>
@@ -43,7 +44,7 @@ public:
        Gateway(Gateway&&) = default;
        Gateway& operator=(Gateway&&) = default;
 
-       void start(void);
+       void start(unsigned int timeout = 0, Timer::Predicate condition = nullptr);
        void stop(void);
 
        template<typename O, typename F>
index 585f72bc45e74395e7064a6c0ea0f4f71aa4e532..45b680b7211e48f637e4a20a1fc0b12e1d89cde3 100644 (file)
@@ -45,6 +45,8 @@ void Vistd::start()
        EXPOSE(gateway, *this, &Vistd::query);
 
        gateway.start();
+
+       INFO(VIST) << "Vistd daemon stopped.";
 }
 
 Rows Vistd::query(const std::string& statement)
diff --git a/src/vist/timer.hpp b/src/vist/timer.hpp
new file mode 100644 (file)
index 0000000..54c5641
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2019 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   timer.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief  Simple timer.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <thread>
+
+namespace vist {
+
+struct Timer {
+       using Predicate = std::function<bool()>;
+       using Task = std::function<void()>;
+
+       /// Execute task() once until predicate() is true.
+       static void ExecOnce(Task task, Predicate predicate, unsigned int seconds) {
+               auto worker = std::thread([task, predicate, seconds]() {
+                       while (1) {
+                               std::this_thread::sleep_for(std::chrono::seconds(seconds));
+
+                               if (predicate()) {
+                                       task();
+                                       break;
+                               }
+                       }
+               });
+
+               if (worker.joinable())
+                       worker.join();
+       }
+};
+
+} // namespace vist
index acc030655d3c0158ce69a8149c272612808a8516..88fb9ff61be5307d7c2a7e8367462498fc0e491b 100644 (file)
@@ -24,6 +24,7 @@ namespace transport {
 
 Message Protocol::Recv(Socket& socket)
 {
+       DEBUG(VIST) << "Socket read event occured.";
        Message::Header header;
        const auto& headerBuffer = boost::asio::buffer(&header, sizeof(Message::Header));
        auto readen = boost::asio::read(socket, headerBuffer);
@@ -43,6 +44,7 @@ Message Protocol::Recv(Socket& socket)
 
 void Protocol::Send(Socket& socket, Message& message)
 { 
+       DEBUG(VIST) << "Socket write event occured.";
        const auto& headerBuffer = boost::asio::buffer(&message.header,
                                                                                                   sizeof(Message::Header));
        auto written = boost::asio::write(socket, headerBuffer);
@@ -61,12 +63,13 @@ Message Protocol::Request(Socket& socket, Message& message)
        return Protocol::Recv(socket);
 }
 
-void Protocol::Async::dispatch(const Task& task)
+void Protocol::Async::dispatch(const Task& task, std::atomic<bool>& polling)
 {
+       polling = true;
        auto self = shared_from_this();
        const auto& header = boost::asio::buffer(&this->message.header,
                                                                                         sizeof(Message::Header));
-       auto handler = [self, task](const auto& error, std::size_t size) {
+       auto handler = [self, task, &polling](const auto& error, std::size_t size) {
                if (error) {
                        if (error == boost::asio::error::eof) {
                                DEBUG(VIST) << "Socket EoF event occured.";
@@ -89,13 +92,13 @@ void Protocol::Async::dispatch(const Task& task)
                                << readen << ", " << self->message.size();
 
                self->message.disclose(self->message.signature);
-               self->process(task);
+               self->process(task, polling);
        };
 
        boost::asio::async_read(self->socket, header, handler);
 }
 
-void Protocol::Async::process(const Task& task)
+void Protocol::Async::process(const Task& task, std::atomic<bool>& polling)
 {
        bool raised = false;
        std::string errMsg;
@@ -121,7 +124,7 @@ void Protocol::Async::process(const Task& task)
        auto self = shared_from_this();
        const auto& headerBuffer = boost::asio::buffer(&this->message.header,
                                                                                                   sizeof(Message::Header));
-       auto handler = [self, task](const auto& error, std::size_t size) { 
+       auto handler = [self, task, &polling](const auto& error, std::size_t size) {
                if (error || size != sizeof(Message::Header))
                        THROW(ErrCode::ProtocolBroken) << "Failed to send message header: "
                                                                                   << error.message();
@@ -132,7 +135,7 @@ void Protocol::Async::process(const Task& task)
                        THROW(ErrCode::ProtocolBroken) << "Failed to send message content.";
 
                /// Re-dispatch for next request.
-               self->dispatch(task);
+               self->dispatch(task, polling);
        };
 
        boost::asio::async_write(self->socket, headerBuffer, handler);
index b099acd5de9fff576b1d7c9d08954a77794e64c3..877dd767c91463187176b2af21ed3d5f6ad3db24 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <vist/transport/message.hpp>
 
+#include <atomic>
 #include <functional>
 
 #include <boost/asio.hpp>
@@ -47,8 +48,8 @@ struct Protocol {
        class Async : public std::enable_shared_from_this<Async> {
        public:
                explicit Async(Context& context) : socket(context) {}
-               void dispatch(const Task& task);
-               void process(const Task& task);
+               void dispatch(const Task& task, std::atomic<bool>& polling);
+               void process(const Task& task, std::atomic<bool>& polling);
 
                inline Socket& getSocket()
                {
index eee2b8126158ec15854ba581e9d61f542effb6a1..afb22d8548b5d778b6001d6a359b9643b4274cc1 100644 (file)
 
 #pragma once
 
+#include <vist/timer.hpp>
 #include <vist/exception.hpp>
 #include <vist/logger.hpp>
 #include <vist/transport/protocol.hpp>
 
 #include <memory>
+#include <atomic>
+#include <thread>
+#include <chrono>
 
 #include <unistd.h>
 #include <errno.h>
@@ -35,7 +39,7 @@ namespace transport {
 
 class Server {
 public:
-       Server(const std::string& path, const Protocol::Task& task)
+       Server(const std::string& path, const Protocol::Task& task) : polling(false)
        {
                errno = 0;
                if (::unlink(path.c_str()) == -1 && errno != ENOENT)
@@ -55,15 +59,31 @@ public:
                        if (error)
                                THROW(ErrCode::RuntimeError) << error.message();
 
-                       asyncSession->dispatch(task);
+                       asyncSession->dispatch(task, this->polling);
 
                        this->accept(task);
                };
                this->acceptor->async_accept(asyncSession->getSocket(), handler);
        }
 
-       inline void run()
+       inline void run(unsigned int timeout = 0, Timer::Predicate condition = nullptr)
        {
+               if (timeout > 0) {
+                       auto stopper = [this]() {
+                               INFO(VIST) << "There are no sessions. And timeout is occured.";
+                               this->context.stop();
+                       };
+
+                       auto wrapper = [this, condition]() -> bool {
+                               if (condition)
+                                       return condition() && polling == false;
+
+                               return polling == false;
+                       };
+
+                       Timer::ExecOnce(stopper, wrapper, timeout);
+               }
+
                this->context.run();
        }
 
@@ -75,6 +95,9 @@ public:
 private:
        Protocol::Context context;
        std::unique_ptr<Protocol::Acceptor> acceptor;
+
+       /// check for session is maintained
+       std::atomic<bool> polling;
 };
 
 } // namespace transport
index 5b1d685d97794044ba03667571913aa33c9ecc9e..94262a91c3de2dba1121b474bb9df22ea7812b41 100644 (file)
@@ -103,6 +103,7 @@ TEST(ProtocolTests, sync_server_sync_client)
                serverThread.join();
 }
 
+/* example without polling memeber variable
 TEST(ProtocolTests, async_server_sync_client)
 {
        std::string sockPath = "vist-test.sock";
@@ -169,3 +170,4 @@ TEST(ProtocolTests, async_server_sync_client)
        if (serverThread.joinable())
                serverThread.join();
 }
+*/
index 8c8d4624922d65aa7dc142e50df64a50c0abfb5c..bdc6ed5fdc5fa1ba3f05105ed32cfb2d420f227e 100644 (file)
@@ -3,6 +3,8 @@ Description=Virtual Security Table socket
 
 [Socket]
 ListenStream=/tmp/.vist
+SocketUser=security_fw
+SocketGroup=security_fw
 SocketMode=0777
 SmackLabelIPIn=*
 SmackLabelIPOut=@