diff options
author | Kyungwook Tak <k.tak@samsung.com> | 2017-01-03 14:40:43 +0900 |
---|---|---|
committer | Kyungwook Tak <k.tak@samsung.com> | 2017-01-03 14:41:36 +0900 |
commit | 5f1d1989e7a06177f92f8b59a77dbe41deb3b281 (patch) | |
tree | 24a2fb876e8630fe10592cd5fd5d4fd21c377396 | |
parent | 6aff7acc014aed787a82e5bb4b4ddf9d8f7a2d9a (diff) | |
parent | f80234bc765938c851be148ad79c27456b91998a (diff) | |
download | csr-framework-5f1d1989e7a06177f92f8b59a77dbe41deb3b281.tar.gz csr-framework-5f1d1989e7a06177f92f8b59a77dbe41deb3b281.tar.bz2 csr-framework-5f1d1989e7a06177f92f8b59a77dbe41deb3b281.zip |
Release 2.3.0
* Mainloop backend layer added
* Popup service uses one ecore mainloop
Change-Id: Ic6a140928193c64e908c4168ad868798710b0222
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
22 files changed, 797 insertions, 460 deletions
diff --git a/packaging/csr-framework.spec b/packaging/csr-framework.spec index 7c2b1b7..5325fdd 100644 --- a/packaging/csr-framework.spec +++ b/packaging/csr-framework.spec @@ -22,7 +22,7 @@ Summary: A general purpose content screening and reputation solution Name: csr-framework -Version: 2.2.1 +Version: 2.3.0 Release: 0 Source: %{name}-%{version}.tar.gz License: Apache-2.0 and BSL-1.0 diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 1db36f9..8cad4a3 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -48,7 +48,7 @@ SET(${TARGET_CSR_COMMON}_SRCS common/em-context.cpp common/kvp-container.cpp common/dispatcher.cpp - common/mainloop.cpp + common/native-mainloop.cpp common/service.cpp common/socket.cpp common/socket-descriptor.cpp diff --git a/src/framework/client/async-logic.cpp b/src/framework/client/async-logic.cpp index 43ca501..ebe97f7 100644 --- a/src/framework/client/async-logic.cpp +++ b/src/framework/client/async-logic.cpp @@ -23,19 +23,22 @@ #include <cstdint> #include <utility> -#include <sys/epoll.h> #include "common/exception.h" #include "common/cs-detected.h" #include "common/connection.h" #include "common/async-protocol.h" +#include "common/native-mainloop.h" #include "common/audit/logger.h" namespace Csr { namespace Client { AsyncLogic::AsyncLogic(HandleExt *handle, void *userdata) : - m_handle(handle), m_userdata(userdata), m_dispatcherAsync(new Dispatcher(SockId::CS)) + m_loop(new NativeMainloop()), + m_handle(handle), + m_userdata(userdata), + m_dispatcherAsync(new Dispatcher(SockId::CS)) { } @@ -63,15 +66,15 @@ void AsyncLogic::scanHelper(const CommandId &id, const StrSet &s) auto fd = this->m_dispatcherAsync->getFd(); auto cancelEventFd = this->m_cancelSignal.getFd(); - this->m_loop.addEventSource(cancelEventFd, EPOLLIN, - [&](uint32_t) { + this->m_loop->addEventSource(cancelEventFd, Mainloop::Event::READ, + [&](Mainloop::Event) { this->m_cancelSignal.receive(); ThrowExcInfo(ASYNC_EVENT_CANCEL, "Async event cancelled on fd: " << fd); }); - this->m_loop.addEventSource(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [&](uint32_t e) { - if (e & (EPOLLHUP | EPOLLRDHUP)) + this->m_loop->addEventSource(fd, Mainloop::Event::READ | Mainloop::Event::CLOSE, + [&](Mainloop::Event e) { + if ((e & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) ThrowExc(CSR_ERROR_SOCKET, "csr-server might be crashed. Finish async client loop"); // read event @@ -121,8 +124,7 @@ void AsyncLogic::scanHelper(const CommandId &id, const StrSet &s) }); try { - while (true) - this->m_loop.dispatch(-1); + this->m_loop->run(-1); } catch (const Exception &e) { switch (e.error()) { case ASYNC_EVENT_COMPLETE: diff --git a/src/framework/client/async-logic.h b/src/framework/client/async-logic.h index 7e82857..6ef4b58 100644 --- a/src/framework/client/async-logic.h +++ b/src/framework/client/async-logic.h @@ -46,9 +46,9 @@ public: private: void scanHelper(const CommandId &id, const StrSet &s); + std::unique_ptr<Mainloop> m_loop; HandleExt *m_handle; // for registering results for auto-release void *m_userdata; - Mainloop m_loop; EventFd m_cancelSignal; std::unique_ptr<Dispatcher> m_dispatcherAsync; }; diff --git a/src/framework/common/mainloop.h b/src/framework/common/mainloop.h index 18b04d2..3333214 100644 --- a/src/framework/common/mainloop.h +++ b/src/framework/common/mainloop.h @@ -1,40 +1,41 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 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 + * 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 + * 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 mainloop.h - * @author Kyungwook Tak (k.tak@samsung.com) - * @version 1.0 - * @brief Manageloop of csr-server with epoll + * 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. */ #pragma once #include <functional> -#include <mutex> -#include <unordered_map> +#include <utility> +#include <type_traits> #include "common/macros.h" namespace Csr { -class API Mainloop { +class Mainloop { public: - using Callback = std::function<void(uint32_t event)>; + enum class Event : uint32_t { + NONE = 0, + READ = 1 << 0, + WRITE = 1 << 1, + CLOSE = 1 << 2 + }; + + using Callback = std::function<void(Event event)>; - Mainloop(); - virtual ~Mainloop(); + Mainloop() : m_domainSourceNum(0) {} + virtual ~Mainloop() {} Mainloop(const Mainloop &) = delete; Mainloop &operator=(const Mainloop &) = delete; @@ -43,27 +44,48 @@ public: // timeout unit: seconds // if timeout is negative value, no timeout on idle. - void run(int timeout); + virtual void run(int timeout) = 0; - // Moved to public to customize stop condition - void dispatch(int timeout); + virtual void addEventSource(int fd, Event event, Callback &&callback) = 0; + virtual void removeEventSource(int fd) = 0; - void addEventSource(int fd, uint32_t event, Callback &&callback); - void removeEventSource(int fd); - size_t countEventSource(void) const; + void addDomainEventSource(int fd, Event event, Callback &&callback) + { + ++this->m_domainSourceNum; + this->addEventSource(fd, event, std::move(callback)); + } - void setIdleChecker(std::function<bool()> &&idleChecker); +protected: + size_t m_domainSourceNum; +}; -private: +template<typename T> using Underlying = typename std::underlying_type<T>::type; +template<typename T> +constexpr Underlying<T> underlying(T t) { return Underlying<T>(t); } - bool m_isTimedOut; - int m_pollfd; - mutable std::mutex m_mutex; - std::unordered_map<int, Callback> m_callbacks; +inline constexpr Mainloop::Event operator&(Mainloop::Event e1, Mainloop::Event e2) +{ + return Mainloop::Event(underlying(e1) & underlying(e2)); +} - std::function<bool()> m_isIdle; +inline Mainloop::Event &operator&=(Mainloop::Event &e1, Mainloop::Event e2) +{ + return e1 = e1 & e2; +} - constexpr static size_t MAX_EPOLL_EVENTS = 32; -}; +inline constexpr Mainloop::Event operator|(Mainloop::Event e1, Mainloop::Event e2) +{ + return Mainloop::Event(underlying(e1) | underlying(e2)); +} +inline Mainloop::Event &operator|=(Mainloop::Event &e1, Mainloop::Event e2) +{ + return e1 = e1 | e2; } + +inline constexpr Mainloop::Event operator~(Mainloop::Event e) +{ + return Mainloop::Event(~underlying(e)); +} + +} // namespace Csr diff --git a/src/framework/common/mainloop.cpp b/src/framework/common/native-mainloop.cpp index 55eb7c8..8e2de51 100644 --- a/src/framework/common/mainloop.cpp +++ b/src/framework/common/native-mainloop.cpp @@ -14,12 +14,12 @@ * limitations under the License */ /* - * @file mainloop.cpp + * @file native-mainloop.cpp * @author Kyungwook Tak (k.tak@samsung.com) * @version 1.0 * @brief Mainloop of csr-server with epoll */ -#include "common/mainloop.h" +#include "common/native-mainloop.h" #include <system_error> #include <sys/epoll.h> @@ -30,7 +30,35 @@ namespace Csr { -Mainloop::Mainloop() : +uint32_t NativeMainloop::convertFlags(Mainloop::Event events) +{ + uint32_t flags = 0; + + if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE) + flags |= EPOLLIN; + if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE) + flags |= EPOLLOUT; + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) + flags |= (EPOLLHUP | EPOLLRDHUP); + + return flags; +} + +Mainloop::Event NativeMainloop::convertFlags(uint32_t events) +{ + Mainloop::Event flags = Mainloop::Event::NONE; + + if (events & EPOLLIN) + flags |= Mainloop::Event::READ; + if (events & EPOLLOUT) + flags |= Mainloop::Event::WRITE; + if (events & (EPOLLHUP | EPOLLRDHUP)) + flags |= Mainloop::Event::CLOSE; + + return flags; +} + +NativeMainloop::NativeMainloop() : m_isTimedOut(false), m_pollfd(::epoll_create1(EPOLL_CLOEXEC)) { @@ -40,7 +68,7 @@ Mainloop::Mainloop() : "Failed to epoll_create1"); } -Mainloop::~Mainloop() +NativeMainloop::~NativeMainloop() { if (!this->m_isTimedOut && !this->m_callbacks.empty()) ERROR("mainloop registered callbacks should be empty except timed out case"); @@ -48,7 +76,7 @@ Mainloop::~Mainloop() ::close(m_pollfd); } -void Mainloop::run(int timeout) +void NativeMainloop::run(int timeout) { this->m_isTimedOut = false; @@ -56,21 +84,23 @@ void Mainloop::run(int timeout) this->dispatch(timeout); } - DEBUG("Mainloop run stopped"); + DEBUG("NativeMainloop run stopped"); } -void Mainloop::addEventSource(int fd, uint32_t event, Callback &&callback) +void NativeMainloop::addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) { std::lock_guard<std::mutex> l(this->m_mutex); if (this->m_callbacks.count(fd) != 0) ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!"); - DEBUG("Add event[" << event << "] source on fd[" << fd << "]"); + DEBUG("Add event[" << static_cast<uint32_t>(event) + << "] source on fd[" << fd << "]"); epoll_event e; - e.events = event; + e.events = NativeMainloop::convertFlags(event); e.data.fd = fd; if (::epoll_ctl(m_pollfd, EPOLL_CTL_ADD, fd, &e) == -1) @@ -81,16 +111,17 @@ void Mainloop::addEventSource(int fd, uint32_t event, Callback &&callback) this->m_callbacks[fd] = std::move(callback); } -void Mainloop::removeEventSource(int fd) +void NativeMainloop::removeEventSource(int fd) { std::lock_guard<std::mutex> l(this->m_mutex); - if (this->m_callbacks.count(fd) == 0) + auto it = this->m_callbacks.find(fd); + if (it == this->m_callbacks.end()) ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] isn't added at all"); DEBUG("Remove event source on fd[" << fd << "]"); - this->m_callbacks.erase(fd); + this->m_callbacks.erase(it); if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) { if (errno == ENOENT) @@ -102,18 +133,12 @@ void Mainloop::removeEventSource(int fd) } } -size_t Mainloop::countEventSource() const -{ - std::lock_guard<std::mutex> l(this->m_mutex); - return this->m_callbacks.size(); -} - -void Mainloop::dispatch(int timeout) +void NativeMainloop::dispatch(int timeout) { int nfds = -1; epoll_event event[MAX_EPOLL_EVENTS]; - DEBUG("Mainloop dispatched with timeout: " << timeout); + DEBUG("NativeMainloop dispatched with timeout: " << timeout); do { nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS, @@ -126,13 +151,13 @@ void Mainloop::dispatch(int timeout) "epoll_wait failed!"); if (nfds == 0) { - DEBUG("Mainloop timed out!"); - if (this->m_isIdle && !this->m_isIdle()) { - INFO("Mainloop timed out but there's running task on upper layer. " + DEBUG("NativeMainloop timed out!"); + if (this->m_callbacks.size() > this->m_domainSourceNum) { + INFO("NativeMainloop timed out but there's running task on upper layer. " "Re-dispatch."); this->m_isTimedOut = false; } else { - INFO("Mainloop timed out! stop the loop!"); + INFO("NativeMainloop timed out! stop the loop!"); this->m_isTimedOut = true; } @@ -142,24 +167,22 @@ void Mainloop::dispatch(int timeout) for (int i = 0; i < nfds; i++) { int fd = event[i].data.fd; - if (this->m_callbacks.count(fd) == 0) + auto it = this->m_callbacks.find(fd); + if (it == this->m_callbacks.end()) ThrowExc(CSR_ERROR_SERVER, "event in on fd[" << fd << "] but associated callback isn't exist!"); - if (event[i].events & (EPOLLHUP | EPOLLRDHUP)) { + auto events = convertFlags(event[i].events); + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) { INFO("peer connection closed on fd[" << fd << "]"); - event[i].events &= ~EPOLLIN; + events &= ~Mainloop::Event::READ; } - DEBUG("event[" << event[i].events << "] polled on fd[" << fd << "]"); + DEBUG("event[" << static_cast<uint32_t>(events) + << "] polled on fd[" << fd << "]"); - this->m_callbacks[fd](event[i].events); + it->second(events); } } -void Mainloop::setIdleChecker(std::function<bool()> &&idleChecker) -{ - this->m_isIdle = std::move(idleChecker); -} - } diff --git a/src/framework/common/native-mainloop.h b/src/framework/common/native-mainloop.h new file mode 100644 index 0000000..04d6fa1 --- /dev/null +++ b/src/framework/common/native-mainloop.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 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 native-mainloop.h + * @author Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief Manageloop of csr-server with epoll + */ +#pragma once + +#include <functional> +#include <mutex> +#include <unordered_map> + +#include "common/mainloop.h" +#include "common/macros.h" + +namespace Csr { + +class API NativeMainloop : public Mainloop { +public: + NativeMainloop(); + virtual ~NativeMainloop(); + + virtual void run(int timeout) override; + virtual void addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) override; + virtual void removeEventSource(int fd) override; + +private: + void dispatch(int timeout); + static uint32_t convertFlags(Mainloop::Event events); + static Mainloop::Event convertFlags(uint32_t events); + + bool m_isTimedOut; + int m_pollfd; + mutable std::mutex m_mutex; + std::unordered_map<int, Mainloop::Callback> m_callbacks; + + constexpr static size_t MAX_EPOLL_EVENTS = 32; +}; + +} diff --git a/src/framework/common/service.cpp b/src/framework/common/service.cpp index aef65e6..36430d0 100644 --- a/src/framework/common/service.cpp +++ b/src/framework/common/service.cpp @@ -30,8 +30,12 @@ namespace Csr { -Service::Service() noexcept +Service::Service(Mainloop *mainloop) { + if (mainloop == nullptr) + throw std::invalid_argument("mainloop shouldn't be null"); + + this->m_loop.reset(mainloop); } Service::~Service() @@ -53,16 +57,18 @@ void Service::start(int timeout) DEBUG("Get systemd socket[" << socket->getFd() << "] for sock id: " << static_cast<int>(id)); - this->m_loop.addEventSource(socket->getFd(), EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [this, socket](uint32_t event) { - if (event != EPOLLIN) - return; + this->m_loop->addDomainEventSource( + socket->getFd(), + Mainloop::Event::READ | Mainloop::Event::CLOSE, + [this, socket](Mainloop::Event events) { + if ((events & Mainloop::Event::READ) == Mainloop::Event::NONE) + return; - this->onNewConnection(std::make_shared<Connection>(socket->accept())); - }); + this->onNewConnection(std::make_shared<Connection>(socket->accept())); + }); } - this->m_loop.run(timeout); + this->m_loop->run(timeout); } void Service::onNewConnection(ConnShPtr &&connection) @@ -74,28 +80,29 @@ void Service::onNewConnection(ConnShPtr &&connection) INFO("welcome! accepted client socket fd[" << fd << "]"); - this->m_loop.addEventSource(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [&, fd](uint32_t event) { - std::lock_guard<std::mutex> lock(this->m_crMtx); + this->m_loop->addEventSource(fd, + Mainloop::Event::READ | Mainloop::Event::CLOSE, + [&, fd](Mainloop::Event events) { + std::lock_guard<std::mutex> lock(this->m_crMtx); - DEBUG("read event comes in to fd[" << fd << "]"); + DEBUG("read event comes in to fd[" << fd << "]"); - if (this->m_connectionRegistry.count(fd) == 0) - ThrowExc(CSR_ERROR_SERVER, "get event on fd[" << fd << - "] but no associated connection exist"); + auto it = this->m_connectionRegistry.find(fd); + if (it == this->m_connectionRegistry.end()) + ThrowExc(CSR_ERROR_SERVER, "get event on fd[" << fd << + "] but no associated connection exist"); - auto &conn = this->m_connectionRegistry[fd]; - - if (event & (EPOLLHUP | EPOLLRDHUP)) { - DEBUG("event of epoll hup. close connection on fd[" << fd << "]"); - this->onCloseConnection(conn); - return; - } + auto &conn = it->second; - DEBUG("Start message process on fd[" << fd << "]"); + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) { + DEBUG("close event occured. close connection on fd[" << fd << "]"); + this->onCloseConnection(conn); + return; + } - onMessageProcess(conn); - }); + this->onMessageProcess(conn); + } + ); std::lock_guard<std::mutex> lock(this->m_crMtx); this->m_connectionRegistry[fd] = std::move(connection); @@ -108,15 +115,15 @@ void Service::onCloseConnection(const ConnShPtr &connection) auto fd = connection->getFd(); - if (this->m_connectionRegistry.count(fd) == 0) + auto it = this->m_connectionRegistry.find(fd); + if (it == this->m_connectionRegistry.end()) ThrowExc(CSR_ERROR_SERVER, "no connection in registry to remove " "associated to fd[" << fd << "]"); INFO("good-bye! close socket fd[" << fd << "]"); - this->m_loop.removeEventSource(fd); - - this->m_connectionRegistry.erase(fd); + this->m_loop->removeEventSource(fd); + this->m_connectionRegistry.erase(it); } } diff --git a/src/framework/common/service.h b/src/framework/common/service.h index 0e4195c..77ca336 100644 --- a/src/framework/common/service.h +++ b/src/framework/common/service.h @@ -21,9 +21,9 @@ */ #pragma once -#include <string> -#include <functional> #include <set> +#include <memory> +#include <unordered_map> #include <mutex> #include "common/macros.h" @@ -35,7 +35,7 @@ namespace Csr { class API Service { public: - Service() noexcept; + Service(Mainloop *mainloop); virtual ~Service(); Service(const Service &) = delete; @@ -47,7 +47,7 @@ public: virtual void start(int timeout) final; protected: - Mainloop m_loop; + std::unique_ptr<Mainloop> m_loop; private: virtual void onMessageProcess(const ConnShPtr &) = 0; diff --git a/src/framework/common/socket.h b/src/framework/common/socket.h index 52a6a8a..24fd296 100644 --- a/src/framework/common/socket.h +++ b/src/framework/common/socket.h @@ -23,7 +23,6 @@ #include <string> -#include "common/macros.h" #include "common/types.h" #include "common/socket-descriptor.h" diff --git a/src/framework/service/file-system.cpp b/src/framework/service/file-system.cpp index 2422a4d..8458052 100644 --- a/src/framework/service/file-system.cpp +++ b/src/framework/service/file-system.cpp @@ -301,54 +301,73 @@ void FsVisitor::run(const DirPtr &dirptr, const FilePtr ¤tdir) auto fullpath = (parent_dirpath.back() == '/') ? (parent_dirpath + name) : (parent_dirpath + "/" + name); - if (result->d_type == DT_DIR) { + INFO("start to traverse file: " << fullpath); + + if (result->d_type == DT_LNK) { + if (!currentdir->isInApp()) + continue; + + auto stat = getStat(fullpath); + if (S_ISREG(stat->st_mode)) + this->visitFile(fullpath, currentdir); + else if (S_ISDIR(stat->st_mode)) + this->visitDir(fullpath, currentdir); + + } else if (result->d_type == DT_DIR) { if ((name_size == 1 && name[0] == '.') || (name_size == 2 && name[0] == '.' && name[1] == '.')) continue; - FilePtr ncurrentdir; - try { - ncurrentdir = File::create(fullpath, currentdir); - } catch (const Exception &e) { - if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) { - WARN("Perm denied to create file on pkg path: " << fullpath); - continue; - } else { - throw; - } - } - - if (this->m_isBasedOnName && ncurrentdir->isInApp()) { - this->m_targetHandler(ncurrentdir); - } else { - auto ndirptr = openDir(fullpath); - if (ndirptr == nullptr) { - WARN("Failed to open dir: " << fullpath << " with errno: " << errno); - continue; - } - - DEBUG("recurse dir : " << fullpath); - this->run(ndirptr, ncurrentdir); - } + this->visitDir(fullpath, currentdir); } else if (result->d_type == DT_REG) { - try { - auto fileptr = File::createIfModified(fullpath, currentdir, this->m_since); - - if (fileptr) - this->m_targetHandler(fileptr); - } catch (const Exception &e) { - if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) - WARN("file not exist: " << fullpath << " msg: " << e.what()); - else if (e.error() == CSR_ERROR_FILE_SYSTEM) - WARN("file type is not regular...? can it be happened?" - " :" << fullpath << " msg: " << e.what()); - else - throw; - } + this->visitFile(fullpath, currentdir); } } } +void FsVisitor::visitDir(const std::string &fullpath, const FilePtr ¤tdir) +{ + FilePtr ncurrentdir; + + try { + ncurrentdir = File::create(fullpath, currentdir); + } catch (const Exception &e) { + if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) { + WARN("Perm denied to create file on pkg path: " << fullpath); + return; + } else { + throw; + } + } + + if (this->m_isBasedOnName && ncurrentdir->isInApp()) { + this->m_targetHandler(ncurrentdir); + } else { + if (auto ndirptr = openDir(fullpath)) { + DEBUG("recurse dir: " << fullpath); + this->run(ndirptr, ncurrentdir); + } else { + WARN("Failed to open dir: " << fullpath << " with errno: " << errno); + } + } +} + +void FsVisitor::visitFile(const std::string &fullpath, const FilePtr ¤tdir) +{ + try { + if (auto fileptr = File::createIfModified(fullpath, currentdir, this->m_since)) + this->m_targetHandler(fileptr); + } catch (const Exception &e) { + if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) + WARN("file not exist: " << fullpath << " msg: " << e.what()); + else if (e.error() == CSR_ERROR_FILE_SYSTEM) + WARN("file type is not regular...? can it be happened?" + " :" << fullpath << " msg: " << e.what()); + else + throw; + } +} + void FsVisitor::run() { auto currentdir = File::create(this->m_path, nullptr); diff --git a/src/framework/service/file-system.h b/src/framework/service/file-system.h index ee73279..7166c47 100644 --- a/src/framework/service/file-system.h +++ b/src/framework/service/file-system.h @@ -170,6 +170,8 @@ private: using DirPtr = std::unique_ptr<Dir>; void run(const DirPtr &dirptr, const FilePtr ¤tdir); + void visitDir(const std::string &fullpath, const FilePtr ¤tdir); + void visitFile(const std::string &fullpath, const FilePtr ¤tdir); static DirPtr openDir(const std::string &); diff --git a/src/framework/service/server-service.cpp b/src/framework/service/server-service.cpp index 24bd1bf..b540269 100644 --- a/src/framework/service/server-service.cpp +++ b/src/framework/service/server-service.cpp @@ -34,6 +34,7 @@ #include "common/wp-result.h" #include "common/exception.h" #include "common/async-protocol.h" +#include "common/native-mainloop.h" #include "service/exception.h" #include "service/access-control.h" #include "service/core-usage.h" @@ -84,7 +85,7 @@ inline CommandId extractCommandId(BinaryQueue &q) } // namespace anonymous -ServerService::ServerService() : Service(), m_workqueue(5) +ServerService::ServerService() : Service(new NativeMainloop()), m_workqueue(5) { this->m_db = std::make_shared<Db::Manager>(RW_DBSPACE "/.csr.db", RO_DBSPACE); @@ -111,11 +112,6 @@ ServerService::ServerService() : Service(), m_workqueue(5) this->add(SockId::CS); this->add(SockId::WP); this->add(SockId::ADMIN); - - // if task is not running in workqueue, it's idle. - this->m_loop.setIdleChecker([this]()->bool { - return (!this->m_workqueue.isTaskRunning() && this->m_loop.countEventSource() == 3); - }); } RawBuffer ServerService::processCs(const ConnShPtr &conn, RawBuffer &data) diff --git a/src/framework/ui/popup/CMakeLists.txt b/src/framework/ui/popup/CMakeLists.txt index 6f8dd01..ddc667b 100644 --- a/src/framework/ui/popup/CMakeLists.txt +++ b/src/framework/ui/popup/CMakeLists.txt @@ -39,6 +39,7 @@ SET(${TARGET_CSR_POPUP}_SRCS logic.cpp popup.cpp popup-service.cpp + ecore-mainloop.cpp package-info.cpp ${PROJECT_SOURCE_DIR}/src/framework/ui/common.cpp ) diff --git a/src/framework/ui/popup/ecore-mainloop.cpp b/src/framework/ui/popup/ecore-mainloop.cpp new file mode 100644 index 0000000..4e97e60 --- /dev/null +++ b/src/framework/ui/popup/ecore-mainloop.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016 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 "ecore-mainloop.h" + +#include <utility> +#include <exception> + +#include "common/audit/logger.h" + +namespace Csr { +namespace Ui { + +Ecore_Fd_Handler_Flags EcoreMainloop::convertFlags(Mainloop::Event events) +{ + uint32_t flags = 0; + + if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE) + flags |= ECORE_FD_READ; + if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE) + flags |= ECORE_FD_WRITE; + + return static_cast<Ecore_Fd_Handler_Flags>(flags); +} + +Mainloop::Event EcoreMainloop::convertFlags(Ecore_Fd_Handler *handler) +{ + Mainloop::Event flags = Mainloop::Event::NONE; + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) + flags |= Mainloop::Event::READ; + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) + flags |= Mainloop::Event::WRITE; + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) + flags |= Mainloop::Event::CLOSE; + + return flags; +} + +EcoreMainloop::EcoreMainloop() : m_isExitCalled(false), m_timer(nullptr) {} + +EcoreMainloop::~EcoreMainloop() +{ + if (this->m_timer) + ecore_timer_del(this->m_timer); + + if (!this->m_isExitCalled) + elm_exit(); +} + +void EcoreMainloop::run(int timeout) +{ + this->dispatch(timeout); +} + +void EcoreMainloop::dispatch(int timeout) +{ + if (timeout >= 0) { + this->m_timer = ecore_timer_add( + static_cast<double>(timeout), &EcoreMainloop::ecoreTimeoutCb, this); + + if (this->m_timer == nullptr) { + ERROR("Failed to ecore_timer_add()..."); + } + } + + elm_run(); +} + +void EcoreMainloop::addEventSource( + int fd, Mainloop::Event events, Mainloop::Callback &&callback) +{ + auto handler = ecore_main_fd_handler_add( + fd, convertFlags(events), + &EcoreMainloop::ecoreFdCallback, this, nullptr, nullptr); + + if (handler == nullptr) { + ERROR("failed to handle fd(" << fd << ") by ecore_main_fd_handler_add()"); + return; + } + + std::unique_ptr<EventSource> source(new EventSource); + source->callback = std::move(callback); + source->handler = handler; + + this->m_sources[fd] = std::move(source); +} + +void EcoreMainloop::removeEventSource(int fd) +{ + auto it = this->m_sources.find(fd); + + if (it == this->m_sources.end()) { + ERROR("fd(" << fd << ") associated source is not found"); + return; + } + + ecore_main_fd_handler_del(it->second->handler); + + this->m_sources.erase(it); +} + +Eina_Bool EcoreMainloop::ecoreFdCallback(void *data, Ecore_Fd_Handler *handler) +{ + auto mainloop = static_cast<EcoreMainloop *>(data); + + if (mainloop == nullptr) + throw std::invalid_argument("userdata for ecore fd callback is invalid"); + + int fd = ecore_main_fd_handler_fd_get(handler); + + auto it = mainloop->m_sources.find(fd); + if (it == mainloop->m_sources.end() || it->second == nullptr) { + ERROR("no associated source found with fd: " << fd); + return ECORE_CALLBACK_CANCEL; + } + + it->second->callback(convertFlags(handler)); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool EcoreMainloop::ecoreTimeoutCb(void *data) +{ + auto mainloop = static_cast<EcoreMainloop *>(data); + + if (mainloop == nullptr) + throw std::invalid_argument("userdata for ecore timeout callback is invalid"); + + if (mainloop->m_sources.size() == mainloop->m_domainSourceNum) { + INFO("There's no alive connection. Only listening socket opened. " + "Let's exit the ecore main loop!"); + + elm_exit(); + + mainloop->m_timer = nullptr; + mainloop->m_isExitCalled = true; + + return ECORE_CALLBACK_CANCEL; + } else { + INFO("Time out expired but there's alive connection " + "so go ahead to next tick!"); + return ECORE_CALLBACK_RENEW; + } +} + +} // namespace Ui +} // namespace Csr diff --git a/src/framework/ui/popup/ecore-mainloop.h b/src/framework/ui/popup/ecore-mainloop.h new file mode 100644 index 0000000..271b011 --- /dev/null +++ b/src/framework/ui/popup/ecore-mainloop.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 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. + */ +#pragma once + +#include <unordered_map> +#include <memory> +#include <Elementary.h> + +#include "common/mainloop.h" + +namespace Csr { +namespace Ui { + +class EcoreMainloop : public Mainloop { +public: + EcoreMainloop(); + virtual ~EcoreMainloop(); + + virtual void run(int timeout) override; + + virtual void addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) override; + virtual void removeEventSource(int fd) override; + +private: + struct EventSource { + Mainloop::Callback callback; + Ecore_Fd_Handler *handler; + }; + + void dispatch(int timeout); + + static Ecore_Fd_Handler_Flags convertFlags(Mainloop::Event events); + static Mainloop::Event convertFlags(Ecore_Fd_Handler *handler); + + static Eina_Bool ecoreFdCallback(void *data, Ecore_Fd_Handler *handler); + static Eina_Bool ecoreTimeoutCb(void *data); + + std::unordered_map<int, std::unique_ptr<EventSource>> m_sources; + + bool m_isExitCalled; + Ecore_Timer *m_timer; +}; + +} // namespace Ui +} // namespace Csr diff --git a/src/framework/ui/popup/logic.cpp b/src/framework/ui/popup/logic.cpp index ce8c83b..5b1a135 100755..100644 --- a/src/framework/ui/popup/logic.cpp +++ b/src/framework/ui/popup/logic.cpp @@ -57,7 +57,7 @@ void split(const std::string &s, std::string &fileName, std::string &extraPath) extraPath = s.substr(0, idx); } -std::string formatToString(const char *form, std::string arg) +std::string formatToString(const char *form, const std::string &arg) { std::vector<char> buf(PATH_MAX, '\0'); snprintf(buf.data(), buf.size(), form, arg.c_str()); @@ -65,254 +65,168 @@ std::string formatToString(const char *form, std::string arg) } } // namespace anonymous -RawBuffer Logic::csPromptData(const std::string &message, const CsDetected &d) const +void Logic::csPromptData(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - Popup p(2); - - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_DATA_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_DATA_HEADER); + m_popup.setBody(FORMAT( "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); - p.setFooter(CS_PROMPT_DATA_FOOTER); - - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); + m_popup.setFooter(CS_PROMPT_DATA_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)}); } -RawBuffer Logic::csPromptFile(const std::string &message, const CsDetected &d) const +void Logic::csPromptFile(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); std::string fileName, extraPath; split(d.targetName, fileName, extraPath); - Popup p(3); - - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_FILE_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_FILE_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_FILE_NAME, fileName) << "<br>" << "- " << formatToString(LABEL_FILE_PATH, extraPath) << "<br>" << "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); std::string prefix(CS_NOTIFY_FILE_FOOTER); - p.setFooter(FORMAT(prefix << "<br>" << CS_PROMPT_FILE_FOOTER)); - - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); - p.setText(p.m_buttons[2], BTN_DELETE); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_REMOVE)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_buttons[2], &p.m_types[2]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); + m_popup.setFooter(FORMAT(prefix << "<br>" << CS_PROMPT_FILE_FOOTER)); + m_popup.setDetailedUrl(d.detailedUrl); - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED), + Popup::Button(BTN_DELETE, CSR_CS_USER_RESPONSE_REMOVE)}); } -RawBuffer Logic::csPromptApp(const std::string &message, const CsDetected &d) const +void Logic::csPromptApp(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); PackageInfo info(d.pkgId); - Popup p(3); - - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_APP_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_APP_HEADER); + m_popup.setBody(FORMAT( LABEL_APP_NAME << info.getLabel() << "<br>" << LABEL_VERSION << info.getVersion() << "<br>" << LABEL_RISK << risk << " (" << d.malwareName << ")")); - p.setIcon(info.getIconPath()); + m_popup.setIcon(info.getIconPath()); std::string prefix = formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL); - p.setFooter(FORMAT(prefix << "<br>" << CS_PROMPT_APP_FOOTER)); - - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); - p.setText(p.m_buttons[2], BTN_UNINSTALL); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_REMOVE)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_buttons[2], &p.m_types[2]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); + m_popup.setFooter(FORMAT(prefix << "<br>" << CS_PROMPT_APP_FOOTER)); + m_popup.setDetailedUrl(d.detailedUrl); - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED), + Popup::Button(BTN_UNINSTALL, CSR_CS_USER_RESPONSE_REMOVE)}); } -RawBuffer Logic::csNotifyData(const std::string &message, const CsDetected &d) const +void Logic::csNotifyData(const std::string &message, const CsDetected &d) { - Popup p(1); - - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_DATA_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_DATA_HEADER); + m_popup.setBody(FORMAT( "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(CS_NOTIFY_DATA_FOOTER); - - p.setText(p.m_buttons[0], BTN_OK); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); + m_popup.setFooter(CS_NOTIFY_DATA_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_OK, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)}); } -RawBuffer Logic::csNotifyFile(const std::string &message, const CsDetected &d) const +void Logic::csNotifyFile(const std::string &message, const CsDetected &d) { - Popup p(2); std::string fileName, extraPath; split(d.targetName, fileName, extraPath); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_FILE_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_FILE_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_FILE_NAME, fileName) << "<br>" << "- " << formatToString(LABEL_FILE_PATH, extraPath) << "<br>" << "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(CS_NOTIFY_FILE_FOOTER); + m_popup.setFooter(CS_NOTIFY_FILE_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_DELETE); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_REMOVE)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_DELETE, CSR_CS_USER_RESPONSE_REMOVE)}); } -RawBuffer Logic::csNotifyApp(const std::string &message, const CsDetected &d) const +void Logic::csNotifyApp(const std::string &message, const CsDetected &d) { PackageInfo info(d.pkgId); - Popup p(2); - - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_APP_HEADER); - p.setIcon(info.getIconPath()); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_APP_HEADER); + m_popup.setIcon(info.getIconPath()); + m_popup.setBody(FORMAT( LABEL_APP_NAME << info.getLabel() << "<br>" << LABEL_VERSION << info.getVersion() << "<br>" << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL)); + m_popup.setFooter(formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL)); + m_popup.setDetailedUrl(d.detailedUrl); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_UNINSTALL); - - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_UNINSTALL, CSR_CS_USER_RESPONSE_REMOVE)}); } -RawBuffer Logic::wpPrompt(const std::string &message, const UrlItem &item) const +void Logic::wpPrompt(const std::string &message, const UrlItem &item) { std::string risk(item.risk == CSR_WP_RISK_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - Popup p(2); - - p.setMessage(message); - p.setTitle(WP_TITLE); - p.setHeader(WP_PROMPT_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(WP_TITLE); + m_popup.setHeader(WP_PROMPT_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_URL, item.url) << "<br>" << "- " << LABEL_RISK << risk)); - p.setFooter(WP_PROMPT_FOOTER); + m_popup.setFooter(WP_PROMPT_FOOTER); + m_popup.setDetailedUrl(item.url); - p.setText(p.m_buttons[0], BTN_BLOCK); - p.setText(p.m_buttons[1], BTN_VIEW); - - p.m_types.emplace_back( - static_cast<int>(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( - static_cast<int>(CSR_WP_USER_RESPONSE_PROCESSING_ALLOWED)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, item.url); - - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_BLOCK, CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_VIEW, CSR_WP_USER_RESPONSE_PROCESSING_ALLOWED)}); } -RawBuffer Logic::wpNotify(const std::string &message, const UrlItem &item) const +void Logic::wpNotify(const std::string &message, const UrlItem &item) { - Popup p(1); - - p.setMessage(message); - p.setTitle(WP_TITLE); - p.setHeader(WP_NOTIFY_HEADER); - p.setBody(FORMAT( + m_popup.reset(); + m_popup.setMessage(message); + m_popup.setTitle(WP_TITLE); + m_popup.setHeader(WP_NOTIFY_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_URL, item.url) << "<br>" << "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH)); - p.setFooter(WP_NOTIFY_FOOTER); - - p.setText(p.m_buttons[0], BTN_OK); - - p.m_types.emplace_back(static_cast<int>(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_hypertext, item.url); + m_popup.setFooter(WP_NOTIFY_FOOTER); + m_popup.setDetailedUrl(item.url); - p.run(); - return p.getResult(); + m_popup.setButtons({ + Popup::Button(BTN_OK, CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)}); } } // namespace Ui } // namespace Csr diff --git a/src/framework/ui/popup/logic.h b/src/framework/ui/popup/logic.h index 50a50dd..bdde6cd 100644 --- a/src/framework/ui/popup/logic.h +++ b/src/framework/ui/popup/logic.h @@ -26,24 +26,32 @@ #include "common/types.h" #include "common/cs-detected.h" #include "ui/common.h" +#include "popup.h" namespace Csr { namespace Ui { class Logic { public: - Logic() = default; - virtual ~Logic() = default; - - RawBuffer csPromptData(const std::string &, const CsDetected &) const; - RawBuffer csPromptApp(const std::string &, const CsDetected &) const; - RawBuffer csPromptFile(const std::string &, const CsDetected &) const; - RawBuffer csNotifyData(const std::string &, const CsDetected &) const; - RawBuffer csNotifyApp(const std::string &, const CsDetected &) const; - RawBuffer csNotifyFile(const std::string &, const CsDetected &) const; - - RawBuffer wpPrompt(const std::string &, const UrlItem &) const; - RawBuffer wpNotify(const std::string &, const UrlItem &) const; + Logic() {} + virtual ~Logic() {} + + void csPromptData(const std::string &, const CsDetected &); + void csPromptApp(const std::string &, const CsDetected &); + void csPromptFile(const std::string &, const CsDetected &); + void csNotifyData(const std::string &, const CsDetected &); + void csNotifyApp(const std::string &, const CsDetected &); + void csNotifyFile(const std::string &, const CsDetected &); + + void wpPrompt(const std::string &, const UrlItem &); + void wpNotify(const std::string &, const UrlItem &); + + void setSender(Popup::Sender &&sender) { + m_popup.setSender(std::move(sender)); + } + +private: + Popup m_popup; }; } // namespace Ui diff --git a/src/framework/ui/popup/popup-service.cpp b/src/framework/ui/popup/popup-service.cpp index 186b847..43ed62f 100644 --- a/src/framework/ui/popup/popup-service.cpp +++ b/src/framework/ui/popup/popup-service.cpp @@ -1,30 +1,27 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 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 + * 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 + * 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 popup-service.cpp - * @author Kyungwook Tak (k.tak@samsung.com) - * @version 1.0 - * @brief + * 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 "popup-service.h" #include "common/binary-queue.h" #include "common/audit/logger.h" +#include "common/types.h" #include "common/exception.h" -#include "common/cs-detected.h" + +#include "ecore-mainloop.h" namespace Csr { namespace Ui { @@ -51,22 +48,30 @@ bool isCsCommand(const CommandId &cid) } } -} // namespace nonymous +} // namespace anonymous -PopupService::PopupService() : Service() +PopupService::PopupService() : Csr::Service(new EcoreMainloop()) { this->add(SockId::POPUP); } -RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) +void PopupService::onMessageProcess(const ConnShPtr &conn) { + auto in = conn->receive(); + + // some fd handler from mainloop makes empty read event when client + // close connection. returning false from process() means connection + // is closed + if (in.empty()) + throw std::invalid_argument("empty read event!"); + BinaryQueue q; - q.push(data); + q.push(std::move(in)); int intCid; q.Deserialize(intCid); - INFO("Request dispatch on popup-service. CommandId: " << static_cast<int>(intCid)); + INFO("Request dispatch on popup service. CommandId: " << static_cast<int>(intCid)); if (isCsCommand(static_cast<Ui::CommandId>(intCid))) { std::string message; @@ -75,22 +80,28 @@ RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) switch (static_cast<Ui::CommandId>(intCid)) { case CommandId::CS_PROMPT_DATA: - return m_logic.csPromptData(message, d); + m_logic.csPromptData(message, d); + break; case CommandId::CS_PROMPT_APP: - return m_logic.csPromptApp(message, d); + m_logic.csPromptApp(message, d); + break; case CommandId::CS_PROMPT_FILE: - return m_logic.csPromptFile(message, d); + m_logic.csPromptFile(message, d); + break; case CommandId::CS_NOTIFY_DATA: - return m_logic.csNotifyData(message, d); + m_logic.csNotifyData(message, d); + break; case CommandId::CS_NOTIFY_APP: - return m_logic.csNotifyApp(message, d); + m_logic.csNotifyApp(message, d); + break; case CommandId::CS_NOTIFY_FILE: - return m_logic.csNotifyFile(message, d); + m_logic.csNotifyFile(message, d); + break; default: ThrowExc(CSR_ERROR_SERVER, "protocol error. invalid ui command id."); @@ -102,25 +113,19 @@ RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) switch (static_cast<Ui::CommandId>(intCid)) { case CommandId::WP_PROMPT: - return m_logic.wpPrompt(message, item); + m_logic.wpPrompt(message, item); + break; case CommandId::WP_NOTIFY: - return m_logic.wpNotify(message, item); + m_logic.wpNotify(message, item); + break; default: ThrowExc(CSR_ERROR_SERVER, "protocol error. invalid ui command id."); } } -} - -void PopupService::onMessageProcess(const ConnShPtr &connection) -{ - DEBUG("process message on popup service"); - - auto in = connection->receive(); - connection->send(this->process(connection, in)); - DEBUG("process done on popup service"); + m_logic.setSender([conn](const RawBuffer &out) { conn->send(out); }); } } // namespace Ui diff --git a/src/framework/ui/popup/popup.cpp b/src/framework/ui/popup/popup.cpp index 46a0cd3..7c8d3ec 100644 --- a/src/framework/ui/popup/popup.cpp +++ b/src/framework/ui/popup/popup.cpp @@ -43,8 +43,20 @@ namespace { } -Popup::Popup(int buttonN) +void Popup::setSender(Sender &&sender) { + m_sender = std::move(sender); +} + +Popup::Popup() : m_win(nullptr) +{ + ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, this); +} + +void Popup::reset() +{ + clear(); + // Set win properties. m_win = elm_win_add(nullptr, "CSR popup", ELM_WIN_NOTIFICATION); elm_win_indicator_opacity_set(m_win, ELM_WIN_INDICATOR_TRANSLUCENT); @@ -56,7 +68,6 @@ Popup::Popup(int buttonN) setRotationToWin(m_win); eext_win_keygrab_set(m_win, HOME_KEY.c_str()); - ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, NULL); // Set popup properties. m_popup = elm_popup_add(m_win); @@ -105,22 +116,11 @@ Popup::Popup(int buttonN) elm_box_pack_end(m_box, m_footer); evas_object_show(m_footer); - // Add buttons dynamically. m_btnBox = elm_box_add(m_popup); setDefaultProperties(m_btnBox); elm_box_horizontal_set(m_btnBox, EINA_TRUE); elm_box_padding_set(m_btnBox, 0, 0); - for(int i=1 ; i <= buttonN; i++) { - std::string id("button" + std::to_string(i)); - Evas_Object *button = elm_button_add(m_popup); - elm_object_style_set(button, "bottom"); - setDefaultProperties(button); - elm_box_pack_end(m_btnBox, button); - evas_object_show(button); - m_buttons.emplace_back(button); - } - elm_box_pack_end(m_box, m_btnBox); evas_object_show(m_btnBox); @@ -132,7 +132,25 @@ Popup::Popup(int buttonN) Popup::~Popup() { - evas_object_del(m_win); + if (m_win != nullptr) + evas_object_del(m_win); +} + +void Popup::setButtons(const std::vector<Popup::Button> &buttons) +{ + for (auto &button : buttons) { + Evas_Object *obj = elm_button_add(m_btnBox); + + elm_object_style_set(obj, "bottom"); + setDefaultProperties(obj); + + setText(obj, button.text); + m_buttonTypeMap[obj] = button.type; + evas_object_smart_callback_add(obj, "clicked", btnClickedCb, this); + + elm_box_pack_end(m_btnBox, obj); + evas_object_show(obj); + } } void Popup::setHeader(const std::string &header) noexcept @@ -163,11 +181,6 @@ void Popup::setIcon(const std::string &path) noexcept elm_image_file_set(m_icon, path.c_str(), NULL); } -void Popup::run(void) -{ - elm_run(); -} - int Popup::response = -1; RawBuffer Popup::getResult(void) @@ -209,19 +222,15 @@ void Popup::setText(Evas_Object *obj, const std::string &text) noexcept elm_object_text_set(obj, text.c_str()); } -void Popup::callbackRegister(Evas_Object *obj, int *type) -{ - evas_object_smart_callback_add(obj, "clicked", btnClickedCb, type); -} - -void Popup::callbackRegister(Evas_Object *obj, const std::string &url) +void Popup::setDetailedUrl(const std::string &url) { if (url.empty()) - evas_object_smart_callback_add( - obj, "anchor,clicked", hypertextClickedCb, &DEFAULT_URL); + m_hypertextUrl = DEFAULT_URL; else - evas_object_smart_callback_add( - obj, "anchor,clicked", hypertextClickedCb, &url); + m_hypertextUrl = url; + + evas_object_smart_callback_add( + m_hypertext, "anchor,clicked", hypertextClickedCb, this); } void Popup::rotationChangedCb(void *data, Evas_Object *, void *) @@ -251,8 +260,12 @@ void Popup::rotationChangedCb(void *data, Evas_Object *, void *) void Popup::hypertextClickedCb(void *data, Evas_Object *, void *) { DEBUG("Launch browser for detailed url."); + auto popup = reinterpret_cast<Popup *>(data); + if (popup == nullptr) + throw std::invalid_argument("Popup instance is null in static callback"); + + auto &url = popup->m_hypertextUrl; - std::string url = *(reinterpret_cast<std::string *>(data)); std::unique_ptr<AppControl> ac(new AppControl); auto ret = app_control_set_operation(ac->handle, APP_CONTROL_OPERATION_VIEW); @@ -274,26 +287,49 @@ void Popup::hypertextClickedCb(void *data, Evas_Object *, void *) } } -void Popup::btnClickedCb(void *data, Evas_Object *, void *) +void Popup::btnClickedCb(void *data, Evas_Object *obj, void *) { - response = *(reinterpret_cast<int *>(data)); - elm_exit(); -} + auto popup = reinterpret_cast<Popup *>(data); + if (popup == nullptr) + throw std::invalid_argument("Popup instance is null in static btnClickedCb"); + response = popup->m_buttonTypeMap.at(obj); + popup->terminateWindow(); +} -Eina_Bool Popup::keyDownCb(void *, int , void *ev) +Eina_Bool Popup::keyDownCb(void *data, int , void *ev) { DEBUG("Key down event caught."); auto event = reinterpret_cast<Ecore_Event_Key *>(ev); - if(event->key == HOME_KEY) { + if (event->key == HOME_KEY) { + auto popup = reinterpret_cast<Popup *>(data); response = -1; - elm_exit(); + popup->terminateWindow(); } // Let the event continue to other callbacks. return ECORE_CALLBACK_PASS_ON; } +void Popup::terminateWindow() +{ + INFO("send result based on response and sender"); + m_sender(getResult()); + + clear(); +} + +void Popup::clear() +{ + if (m_win != nullptr) { + // clear all resources + evas_object_del(m_win); + m_win = nullptr; + } + + m_buttonTypeMap.clear(); +} + } // namespace Ui } // namespace Csr diff --git a/src/framework/ui/popup/popup.h b/src/framework/ui/popup/popup.h index 4475d96..b60bfc7 100644 --- a/src/framework/ui/popup/popup.h +++ b/src/framework/ui/popup/popup.h @@ -32,60 +32,70 @@ #include "common/audit/logger.h" #include "common/binary-queue.h" +#include "common/types.h" namespace Csr { namespace Ui { /* - * -------------------- - * | title | - * ========box========= - * | content(header) | - * |------subBox------| - * |icon|content(body)| - * |------------------| - * | -hypertext | - * | | - * | content(footer) | - * ==================== - * |------btnBox------| - * | button(N) | - * -------------------- + * ------------------------ + * | title | + * |==========box=========| + * || content(header) || + * ||-------subBox-------|| + * |||icon|content(body)||| + * ||--------------------|| + * || -hypertext || + * || content(footer) || + * ||-------btnBox-------|| + * ||| button(N) ||| + * ||--------------------|| + * |======================| */ class Popup { public: - Popup(int buttonN); - virtual ~Popup(); + struct Button { + Button(const char *text, int type) : text(text), type(type) {} - void run(void); - RawBuffer getResult(void); - void setMessage(const std::string &msg) noexcept; + const char *text; + int type; + }; + + Popup(); + virtual ~Popup(); Popup(const Popup &) = delete; Popup &operator=(const Popup &) = delete; Popup(Popup &&) = delete; Popup &operator=(Popup &&) = delete; + void reset(); + + using Sender = std::function<void(const RawBuffer &)>; + void setSender(Sender &&sender); + + void setMessage(const std::string &msg) noexcept; void setTitle(const std::string &title) noexcept; void setHeader(const std::string &header) noexcept; void setBody(const std::string &body) noexcept; void setFooter(const std::string &footer) noexcept; void setIcon(const std::string &path) noexcept; - void setText(Evas_Object *obj, const std::string &text) noexcept; + void setDetailedUrl(const std::string &url); + void setButtons(const std::vector<Button> &buttons); - void callbackRegister(Evas_Object *obj, int *type); - void callbackRegister(Evas_Object *obj, const std::string &url); +private: static void btnClickedCb(void *data, Evas_Object *, void *); static void hypertextClickedCb(void *data, Evas_Object *, void *); static void rotationChangedCb(void *data, Evas_Object *, void *); static Eina_Bool keyDownCb(void *, int, void *); - std::vector<Evas_Object *> m_buttons; - Evas_Object *m_hypertext; - std::vector<int> m_types; + std::map<Evas_Object *, int> m_buttonTypeMap; + void setText(Evas_Object *obj, const std::string &text) noexcept; + void terminateWindow(); + void clear(); -private: + RawBuffer getResult(void); void setDefaultProperties(Evas_Object *obj) noexcept; void setRotationToWin(Evas_Object *obj) noexcept; @@ -98,15 +108,18 @@ private: Evas_Object *m_body; Evas_Object *m_footer; Evas_Object *m_icon; + Evas_Object *m_hypertext; std::string m_message; std::string m_iconPath; std::string m_hypertextUrl; - static int response; - int m_winW; int m_winH; + + Sender m_sender; + + static int response; }; } // namespace Ui diff --git a/test/engine/content-screening/sample-engine.cpp b/test/engine/content-screening/sample-engine.cpp index 34afff7..29634e8 100644 --- a/test/engine/content-screening/sample-engine.cpp +++ b/test/engine/content-screening/sample-engine.cpp @@ -477,14 +477,28 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle, int ret = CSRE_ERROR_NONE; - if (result->d_type & (DT_REG | DT_LNK)) + if (result->d_type == DT_LNK) { + // when the file type is link, check the real file's type(dir or reg file) + // and go ahead to traverse + struct stat s; + if (stat(fullpath.c_str(), &s) != 0) + continue; // failed to get stat + + if (S_ISREG(s.st_mode)) + ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected); + else if (S_ISDIR(s.st_mode)) + ret = csre_cs_scan_app_on_cloud(handle, fullpath.c_str(), &detected); + else + continue; + } else if (result->d_type == DT_REG) { ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected); - else if ((result->d_type & DT_DIR) - && filename.compare("..") != 0 - && filename.compare(".") != 0) + } else if ((result->d_type & DT_DIR) && + filename.compare("..") != 0 && + filename.compare(".") != 0) { ret = csre_cs_scan_app_on_cloud(handle, fullpath.c_str(), &detected); - else + } else { continue; + } if (ret != CSRE_ERROR_NONE) return ret; |