From: Changgyu Choi Date: Tue, 30 Apr 2024 09:02:01 +0000 (+0900) Subject: Modify directory hierarchy X-Git-Tag: accepted/tizen/unified/20240604.015358~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ee2a5c4c8fb8c55cb10134b66f839b462b210af2;p=platform%2Fcore%2Fappfw%2Frpc-port.git Modify directory hierarchy The rpc-port sources have been moved to 'src/rpc-port'. src/ + src/rpc-port Change-Id: I93ab201047ba4bfa424baaf2c80bc5dd6cd53e59 Signed-off-by: Changgyu Choi --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e45a73..b07040e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,36 +1 @@ -AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} RPC_PORT_SRCS) - -ADD_LIBRARY(${TARGET_RPC_PORT} SHARED ${RPC_PORT_SRCS}) -SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES SOVERSION ${MAJORVER}) -SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES VERSION ${FULLVER}) - -TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/../ - ${CMAKE_CURRENT_SOURCE_DIR}/../include) - -APPLY_PKG_CONFIG(${TARGET_RPC_PORT} PUBLIC - AUL_DEPS - BUNDLE_DEPS - CYNARA_CLIENT_DEPS - CYNARA_CREDS_SOCKET_DEPS - DLOG_DEPS - GIO_DEPS - GIO_UNIX_DEPS - GLIB_DEPS - LIBSYSTEMD_DEPS - LIBTZPLATFORM_CONFIG_DEPS - PARCEL_DEPS - PKGMGR_INFO_DEPS - TIZEN_SHARED_QUEUE_DEPS - UUID_DEPS -) - -TARGET_LINK_LIBRARIES(${TARGET_RPC_PORT} PUBLIC "-Wl,-z,nodelete") - -INSTALL(TARGETS ${TARGET_RPC_PORT} DESTINATION ${LIB_INSTALL_DIR}) -INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/ - DESTINATION include/rpc-port - FILES_MATCHING - PATTERN "*.h" -) +ADD_SUBDIRECTORY(rpc-port) diff --git a/src/ac-internal.cc b/src/ac-internal.cc deleted file mode 100644 index 4a746bb..0000000 --- a/src/ac-internal.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 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 "ac-internal.hh" - -#include -#include -#include -#include -#include -#include - -#include - -#include "aul-internal.hh" -#include "cynara_thread.hh" -#include "log-private.hh" - -namespace rpc_port { -namespace internal { -namespace { - -constexpr const uid_t kRegularUidMin = 5000; - -class Cynara { - public: - class Creds { - public: - Creds(int fd, std::string user, std::string client) - : fd_(fd), user_(std::move(user)), client_(std::move(client)) { - _W("client(%s), user(%s), fd(%d)", client_.c_str(), user_.c_str(), fd); - } - - int GetFd() const { return fd_; } - - const std::string& GetUser() const { return user_; } - - const std::string& GetClient() const { return client_; } - - private: - int fd_; - std::string user_; - std::string client_; - }; - - Cynara() : handle_(nullptr, cynara_finish) { - cynara* handle = nullptr; - if (cynara_initialize(&handle, nullptr) != CYNARA_API_SUCCESS) { - _E("cynara_initialize() is failed"); // LCOV_EXCL_LINE - } else { - handle_.reset(handle); - } - } - - ~Cynara() = default; - - std::shared_ptr FetchCredsFromSocket(int fd) { - char* user = nullptr; - int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user); - if (ret != CYNARA_API_SUCCESS) { - // LCOV_EXCL_START - char buf[128] = { 0, }; - cynara_strerror(ret, buf, sizeof(buf)); - _E("cynara_creds_socket_get_user() is failed. fd(%d), error(%d:%s)", - fd, ret, buf); - return nullptr; - // LCOV_EXCL_STOP - } - auto user_auto = std::unique_ptr(user, free); - - char* client = nullptr; - ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client); - if (ret != CYNARA_API_SUCCESS) { - // LCOV_EXCL_START - char buf[128] = { 0, }; - cynara_strerror(ret, buf, sizeof(buf)); - _E("cynara_creds_socket_get_client() is failed. fd(%d), error(%d:%s)", - fd, ret, buf); - return nullptr; - // LCOV_EXCL_STOP - } - auto client_auto = std::unique_ptr(client, free); - - return std::make_shared(fd, user, client); - } - - int Check(const std::shared_ptr& creds, - const std::string& privilege) const { - std::lock_guard lock(mutex_); - _W("cynara_check() ++ privilege(%s), user(%s)", - privilege.c_str(), creds->GetUser().c_str()); - int ret = cynara_check(handle_.get(), creds->GetClient().c_str(), "", - creds->GetUser().c_str(), privilege.c_str()); - _W("cynara_check() -- privilege(%s), user(%s)", - privilege.c_str(), creds->GetUser().c_str()); - if (ret != CYNARA_API_ACCESS_ALLOWED) { - _E("cynara_check() is not allowed. privilege(%s), error(%d)", - privilege.c_str(), ret); - return -1; - } - - return 0; - } - - private: - std::unique_ptr handle_; - mutable std::recursive_mutex mutex_; -}; - -Cynara cynara_inst; - -} // namespace - -void AccessController::AddPrivilege(std::string privilege) { - privileges_.push_back(std::move(privilege)); -} - -void AccessController::SetTrusted(const bool trusted) { - trusted_ = trusted; -} - -int AccessController::CheckPrivilege(int fd) { - auto creds = cynara_inst.FetchCredsFromSocket(fd); - if (creds == nullptr) return -1; - - for (const auto& privilege : privileges_) { - if (cynara_inst.Check(creds, privilege) != 0) - return -1; - } - - return 0; -} - -// LCOV_EXCL_START -int AccessController::CheckTrusted(const std::string& sender_appid) { - if (getuid() < kRegularUidMin) - return 0; - - if (appid_.empty()) - appid_ = Aul::GetAppId(getpid()); - - _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid.c_str()); - pkgmgrinfo_cert_compare_result_type_e res; - int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(appid_.c_str(), - sender_appid.c_str(), getuid(), &res); - if (ret < 0) { - _E("CheckCertificate() Failed"); - return -1; - } - if (res != PMINFO_CERT_COMPARE_MATCH) { - _E("CheckCertificate() Failed : Certificate Not Matched"); - return -1; - } - - return 0; -} -// LCOV_EXCL_STOP - -int AccessController::Check(int fd, const std::string& sender_appid) { - int ret = 0; - if (!privileges_.empty()) { - ret = CheckPrivilege(fd); - if (ret != 0) - return ret; - } - - if (trusted_) - ret = CheckTrusted(sender_appid); - - return ret; -} - -void AccessController::CheckAsync(int fd, std::string sender_appid, - CompleteCallback callback) { - /* This is for handle freed issue */ - auto* tmp_handle = new std::shared_ptr(shared_from_this()); - Job job([=]() -> Job::Type { - if ((*tmp_handle).use_count() == 1) { - delete tmp_handle; // LCOV_EXCL_LINE - return Job::Type::Continue; // LCOV_EXCL_LINE - } - - int res = Check(fd, sender_appid); - auto* cbdata = new std::pair( - std::move(callback), res); - guint sid = g_idle_add( - [](gpointer data) -> gboolean { - auto* cb_data = static_cast*>(data); - auto [callback, res] = *cb_data; - callback(res); - delete cb_data; - return G_SOURCE_REMOVE; - }, cbdata); - if (sid == 0) { - _E("Failed to call g_idle_add"); // LCOV_EXCL_LINE - delete cbdata; // LCOV_EXCL_LINE - } - - delete tmp_handle; - return Job::Type::Continue; - }); - - CynaraThread::GetInst().Push(std::move(job)); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/ac-internal.hh b/src/ac-internal.hh deleted file mode 100644 index 0b48d5c..0000000 --- a/src/ac-internal.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef AC_INTERNAL_HH_ -#define AC_INTERNAL_HH_ - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace rpc_port { -namespace internal { - -using CompleteCallback = std::function; - -class AccessController : public std::enable_shared_from_this { - public: - explicit AccessController(bool trusted = false) : trusted_(trusted) {} - - void AddPrivilege(std::string privilege); - void SetTrusted(const bool trusted); - int Check(int fd, const std::string& sender_appid); - void CheckAsync(int fd, std::string sender_appid, CompleteCallback callback); - - private: - int CheckTrusted(const std::string& sender_appid); - int CheckPrivilege(int fd); - - private: - std::vector privileges_; - std::map cache_; - bool trusted_; - std::string appid_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // AC_INTERNAL_HH_ diff --git a/src/aul-internal.cc b/src/aul-internal.cc deleted file mode 100644 index 628cd5f..0000000 --- a/src/aul-internal.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 -#include -#include - -#include - -#include "aul-internal.hh" -#include "include/rpc-port.h" -#include "log-private.hh" - -namespace rpc_port { -namespace internal { - -std::string Aul::GetName(int pid) { - char* name = nullptr; - if (aul_proc_get_name(pid, &name) != AUL_R_OK) return ""; - - std::unique_ptr name_auto(name, std::free); - return std::string(name); -} - -std::string Aul::GetAppId(int pid) { - char app_id[256] = { 0, }; - int ret = aul_app_get_appid_bypid(pid, app_id, sizeof(app_id)); - if (ret != AUL_R_OK) { - // LCOV_EXCL_START - _E("aul_app_get_appid_bypid() is failed. pid(%d), error(%d)", pid, ret); - return GetName(pid); - // LCOV_EXCL_STOP - } - - return std::string(app_id); -} - -std::string Aul::GetPortPath(const std::string& app_id, - const std::string& port_name, uid_t uid) { - char* port_path = nullptr; - int ret = aul_rpc_port_usr_get_path(app_id.c_str(), port_name.c_str(), uid, - &port_path); - if (ret != AUL_R_OK) { - _E("aul_rpc_port_usr_get_path() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return {}; // LCOV_EXCL_LINE - } - - std::unique_ptr ptr(port_path, std::free); - return std::string(port_path); -} - -int Aul::PrepareStub(const std::string& app_id, const std::string& port_name, - uid_t uid) { - int ret = aul_rpc_port_usr_prepare_stub(app_id.c_str(), port_name.c_str(), - uid); - if (ret != AUL_R_OK) { - _E("aul_rpc_port_usr_prepare_stub() is failed. error(%d)", ret); - if (ret == AUL_R_EILLACC) - return RPC_PORT_ERROR_PERMISSION_DENIED; - - return RPC_PORT_ERROR_IO_ERROR; - } - - return RPC_PORT_ERROR_NONE; -} - -bool Aul::ExistPort(const std::string& app_id, const std::string& port_name, - uid_t uid) { - bool exist = false; - int ret = aul_rpc_port_usr_exist(app_id.c_str(), port_name.c_str(), uid, - &exist); - if (ret != AUL_R_OK) - _W("aul_rpc_port_usr_exist() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return exist; -} - -void Aul::NotifyRpcFinished() { - int ret = aul_rpc_port_notify_rpc_finished(); - if (ret != AUL_R_OK) - _W("aul_rpc_port_notify_rpc_finished() is failed. error(%d)", ret); // LCOV_EXCL_LINE -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/aul-internal.hh b/src/aul-internal.hh deleted file mode 100644 index 3d74be4..0000000 --- a/src/aul-internal.hh +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef AUL_INTERNAL_HH_ -#define AUL_INTERNAL_HH_ - -#include - -namespace rpc_port { -namespace internal { - -class Aul { - public: - static std::string GetName(int pid); - static std::string GetAppId(int pid); - static std::string GetPortPath(const std::string& app_id, - const std::string& port_name, uid_t uid); - static int PrepareStub(const std::string& app_id, - const std::string& port_name, uid_t uid); - static bool ExistPort(const std::string& app_id, const std::string& port_name, - uid_t uid); - static void NotifyRpcFinished(); -}; - -} // namespace internal -} // namespace rpc_port - -#endif // AUL_INTERNAL_HH_ diff --git a/src/client-socket-internal.cc b/src/client-socket-internal.cc deleted file mode 100644 index 9a71b4e..0000000 --- a/src/client-socket-internal.cc +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "client-socket-internal.hh" -#include "exception-internal.hh" -#include "log-private.hh" - -namespace rpc_port { -namespace internal { - -ClientSocket::ClientSocket() { - fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd_ < 0) { - // LCOV_EXCL_START - fd_ = -errno; - _E("socket() is failed. errno(%d)", errno); - THROW(fd_); - // LCOV_EXCL_STOP - } -} - -ClientSocket::ClientSocket(int fd) : fd_(fd) { - SetCloseOnExec(); -} - -ClientSocket::~ClientSocket() { - if (!IsClosed()) - Close(); -} - -void ClientSocket::SetCloseOnExec() { - int flags = fcntl(fd_, F_GETFL, 0); - fcntl(fd_, F_SETFL, flags | FD_CLOEXEC); - _I("Close on exec. fd(%d)", fd_); -} - -void ClientSocket::Close() { - if (fd_ > -1) { - close(fd_); - fd_ = -1; - } -} - -int ClientSocket::Connect(const std::string& endpoint) { - int flag = fcntl(GetFd(), F_GETFL, 0); - fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); - - struct sockaddr_un sockaddr = { 0, }; - sockaddr.sun_family = AF_UNIX; - snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", - endpoint.c_str()); - struct sockaddr* sockaddr_ptr = reinterpret_cast(&sockaddr); - socklen_t len = static_cast(sizeof(sockaddr)); - int ret = connect(GetFd(), sockaddr_ptr, len); - fcntl(GetFd(), F_SETFL, flag); - if (ret < 0) { - // LCOV_EXCL_START - ret = -errno; - _E("connect() is failed. errno(%d)", errno); - return ret; - // LCOV_EXCL_STOP - } - - return 0; -} - -int ClientSocket::Send(const void* buf, unsigned int size) { - const unsigned char* buffer = static_cast(buf); - size_t len = size; - while (len) { - ssize_t bytes = send(GetFd(), buffer, len, MSG_NOSIGNAL); - if (bytes < 0) { - // LCOV_EXCL_START - int ret = -errno; - _E("send() is failed. fd(%d), errno(%d)", GetFd(), errno); - return ret; - // LCOV_EXCL_STOP - } - - len -= bytes; - buffer += bytes; - } - - return 0; -} - -int ClientSocket::Receive(void* buf, unsigned int size) { - unsigned char* buffer = static_cast(buf); - size_t len = size; - while (len) { - ssize_t bytes = read(GetFd(), buffer, len); - if (bytes == 0) { - _W("EOF. fd(%d)", GetFd()); // LCOV_EXCL_START - return -EIO; // LCOV_EXCL_STOP - } - - if (bytes < 0) { - if (errno == EINTR) { - usleep(100 * 1000); - continue; - } - - return -errno; // LCOV_EXCL_LINE - } - - len -= bytes; - buffer += bytes; - } - - return 0; -} - -void ClientSocket::SetReceiveTimeout(int timeout) { - if (timeout == INT_MAX) - return; // LCOV_EXCL_LINE - - if (timeout == -1) - timeout = 5000; - - if (timeout < 0) { - _E("Invalid parameter"); // LCOV_EXCL_LINE - THROW(-EINVAL); // LCOV_EXCL_LINE - } - - struct timeval tv = { - .tv_sec = static_cast(timeout / 1000), - .tv_usec = static_cast((timeout % 1000) * 1000) - }; - socklen_t len = static_cast(sizeof(struct timeval)); - int ret = setsockopt(GetFd(), SOL_SOCKET, SO_RCVTIMEO, &tv, len); - if (ret < 0) { - // LCOV_EXCL_START - ret = -errno; - _E("setsockopt() is failed. errno(%d)", errno); - THROW(ret); - // LCOV_EXCL_STOP - } -} - -bool ClientSocket::IsClosed() { - return fd_ < 0 ? true : false; -} - -int ClientSocket::GetFd() const { - return fd_; -} - -int ClientSocket::RemoveFd() { - int fd = fd_; - fd_ = -1; - return fd; -} - -void ClientSocket::SetNonblock() { - int flag = fcntl(GetFd(), F_GETFL, 0); - fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/client-socket-internal.hh b/src/client-socket-internal.hh deleted file mode 100644 index d033b2e..0000000 --- a/src/client-socket-internal.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef CLIENT_SOCKET_INTERNAL_HH_ -#define CLIENT_SOCKET_INTERNAL_HH_ - -#include - -namespace rpc_port { -namespace internal { - -class ClientSocket { - public: - ClientSocket(); - explicit ClientSocket(int fd); - virtual ~ClientSocket(); - - void Close(); - int Connect(const std::string& endpoint); - int Send(const void* buf, unsigned int size); - int Receive(void* buf, unsigned int size); - void SetReceiveTimeout(int timeout); - bool IsClosed(); - int GetFd() const; - int RemoveFd(); - void SetNonblock(); - void SetCloseOnExec(); - - private: - int fd_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // CLIENT_SOCKET_INTERNAL_HH_ diff --git a/src/cynara_thread.cc b/src/cynara_thread.cc deleted file mode 100644 index a5a2f67..0000000 --- a/src/cynara_thread.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023 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 "cynara_thread.hh" - -#include - -namespace rpc_port { -namespace internal { - -Job::Job(Job::JobHandlerCallback cb) : cb_(std::move(cb)) {} - -Job::Type Job::Do() { - if (cb_ == nullptr) - return Job::Type::Finish; - - return cb_(); -} - -CynaraThread& CynaraThread::GetInst() { - static CynaraThread* inst = new CynaraThread(); - return *inst; -} - -CynaraThread::CynaraThread() { - thread_ = std::thread([this]() { ThreadRun(); }); -} - -// LCOV_EXCL_START -CynaraThread::~CynaraThread() { - queue_.Push(Job()); - thread_.join(); -} -// LCOV_EXCL_STOP - -void CynaraThread::ThreadRun() { - while (true) { - Job job = queue_.WaitAndPop(); - if (job.Do() == Job::Type::Finish) - return; // LCOV_EXCL_LINE - } -} - -void CynaraThread::Push(Job job) { - queue_.Push(std::move(job)); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/cynara_thread.hh b/src/cynara_thread.hh deleted file mode 100644 index 3babdd3..0000000 --- a/src/cynara_thread.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -#ifndef CYNARA_THREAD_HH_ -#define CYNARA_THREAD_HH_ - -#include -#include -#include - -namespace rpc_port { -namespace internal { - -class Job { - public: - enum class Type { - Continue = 0, - Finish = 1, - }; - - using JobHandlerCallback = std::function; - - explicit Job(JobHandlerCallback cb = nullptr); - - ~Job() = default; - - Type Do(); - - private: - JobHandlerCallback cb_; -}; - -class CynaraThread { - public: - static CynaraThread& GetInst(); - CynaraThread(CynaraThread&) = delete; - CynaraThread& operator=(CynaraThread&) = delete; - ~CynaraThread(); - - void ThreadRun(); - void Push(Job job); - - private: - CynaraThread(); - Job Pop(); - - std::thread thread_; - mutable tizen_base::SharedQueue queue_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // CYNARA_THREAD_HH_ diff --git a/src/debug-port-internal.cc b/src/debug-port-internal.cc deleted file mode 100644 index eabe432..0000000 --- a/src/debug-port-internal.cc +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. - * - * 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 "debug-port-internal.hh" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "log-private.hh" -#include "port-internal.hh" - -namespace rpc_port { -namespace internal { -namespace { - -constexpr const char PATH_RPC_PORT_UTIL_SOCK[] = - "/run/aul/daemons/.rpc-port-util-sock"; -constexpr const char ENDPOINT_RPC_PORT_DEBUG[] = "org.tizen.rpcport.debug"; -constexpr const char KEY_PORT_NAME[] = "__K_PORT_NAME__"; - -class Session { - public: - Session(std::string port_name, std::string destination, - int main_port, int delegate_port) - : port_name_(std::move(port_name)), - destination_(std::move(destination)), - main_port_(main_port), - delegate_port_(delegate_port) { - } - - const std::string& GetPortName() const { - return port_name_; - } - - const std::string& GetDestination() const { - return destination_; - } - - int GetMainPort() const { - return main_port_; - } - - int GetDelegatePort() const { - return delegate_port_; - } - - private: - std::string port_name_; - std::string destination_; - int main_port_; - int delegate_port_; -}; - -class DebugPortImpl { - public: - DebugPortImpl() = default; - ~DebugPortImpl(); - - void Dispose(); - bool IsConnected() const; - void AddSession(std::string port_name, std::string destination, - int main_port, int delegate_port); - void RemoveSession(int port); - int Send(int port, bool is_read, uint32_t seq, - const void* buf, unsigned int size); - void Init(); - - private: - int Connect(); - int Watch(int fd); - void Unwatch(); - void SetConnectionStatus(bool status); - void CreateThread(); - void JoinThread(); - - std::recursive_mutex& GetMutex() const; - std::shared_ptr FindSession(int port); - std::shared_ptr FindSession(const std::string& port_name); - - static gboolean OnDebugPortDisconnectedCb(GIOChannel* io, - GIOCondition cond, gpointer data); - static int AppComCb(const char* endpoint, aul_app_com_result_e result, - bundle* envelope, void* user_data); - - private: - bool disposed_ = true; - std::atomic connected_ { false }; - std::unique_ptr port_; - GIOChannel* io_ = nullptr; - guint watch_tag_ = 0; - std::list> sessions_; - std::thread thread_; - std::atomic is_running_ { false }; - tizen_base::SharedQueue> queue_; - mutable std::recursive_mutex mutex_; - aul_app_com_connection_h conn_ = nullptr; -}; - -DebugPortImpl::~DebugPortImpl() { - Dispose(); -} - -void DebugPortImpl::Dispose() { - std::lock_guard lock(GetMutex()); - if (disposed_) - return; - - if (conn_) { - aul_app_com_leave(conn_); - conn_ = nullptr; - } - - Unwatch(); - JoinThread(); - disposed_ = true; -} - -bool DebugPortImpl::IsConnected() const { - return connected_; -} - -void DebugPortImpl::AddSession(std::string port_name, std::string destination, - int main_port, int delegate_port) { - std::lock_guard lock(GetMutex()); - sessions_.emplace_back( - new Session(std::move(port_name), std::move(destination), - main_port, delegate_port)); -} - -void DebugPortImpl::RemoveSession(int port) { - std::lock_guard lock(GetMutex()); - auto iter = std::find_if(sessions_.begin(), sessions_.end(), - [port](std::shared_ptr& sess) -> bool { - return sess->GetMainPort() == port || sess->GetDelegatePort() == port; - }); - - if (iter != sessions_.end()) { - _W("Remove session. port(%d)", port); - iter = sessions_.erase(iter); - } -} - -std::shared_ptr DebugPortImpl::FindSession(int port) { - std::lock_guard lock(GetMutex()); - for (auto& s : sessions_) { - if (s->GetMainPort() == port || s->GetDelegatePort() == port) - return s; - } - - return nullptr; -} - -std::shared_ptr DebugPortImpl::FindSession( - const std::string& port_name) { - std::lock_guard lock(GetMutex()); - for (auto& s : sessions_) { - if (s->GetPortName() == port_name) - return s; - } - - return nullptr; -} - -int DebugPortImpl::Send(int port, bool is_read, uint32_t seq, - const void* buf, unsigned int size) { - if (!IsConnected()) - return 0; - - auto session = FindSession(port); - if (session == nullptr) { - _E("Failed to find session. port(%d)", port); - return -1; - } - - // time + port_name + destination + is_delegate + port + is_read + seq + size + data - tizen_base::Parcel parcel; - parcel.WriteInt64(time(nullptr)); - parcel.WriteString(session->GetPortName().c_str()); - parcel.WriteString(session->GetDestination().c_str()); - parcel.WriteBool(session->GetDelegatePort() == port); - parcel.WriteInt32(port); - parcel.WriteBool(is_read); - parcel.WriteInt32(seq); - parcel.WriteInt32(size); - parcel.Write(static_cast(buf), size); - - queue_.Push(std::make_shared(parcel)); - return 0; -} - -void DebugPortImpl::Init() { - std::lock_guard lock(GetMutex()); - if (!disposed_) - return; - - aul_app_com_create_async(ENDPOINT_RPC_PORT_DEBUG, nullptr, AppComCb, this, - &conn_); - if (conn_ == nullptr) - return; - - do { - int fd = Connect(); - if (fd < 0) - break; - - port_.reset(new Port(fd, "Debug")); - if (Watch(fd) < 0) - break; - - SetConnectionStatus(true); - _W("Connected"); - CreateThread(); - } while (0); - - disposed_ = false; -} - -int DebugPortImpl::Connect() { - if (access(PATH_RPC_PORT_UTIL_SOCK, F_OK) != 0) - return -1; - - int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) { - _E("socket() is failed. errno(%d)", errno); - return -1; - } - - struct sockaddr_un addr = { 0, }; - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_RPC_PORT_UTIL_SOCK); - - int ret = connect(fd, reinterpret_cast(&addr), - sizeof(addr)); - if (ret < 0) { - _E("connect() is failed. fd(%d), errno(%d)", fd, errno); - close(fd); - return -1; - } - - return fd; -} - -int DebugPortImpl::Watch(int fd) { - GIOChannel* io = g_io_channel_unix_new(fd); - if (io == nullptr) { - _E("g_io_channel_unix_new() is failed"); - return -1; - } - - GIOCondition cond = static_cast( - (G_IO_ERR | G_IO_HUP | G_IO_NVAL)); - guint tag = g_io_add_watch(io, cond, OnDebugPortDisconnectedCb, this); - if (tag == 0) { - _E("g_io_add_watch() is failed"); - g_io_channel_unref(io); - return -1; - } - - io_ = io; - watch_tag_ = tag; - return 0; -} - -void DebugPortImpl::Unwatch() { - if (io_) { - g_io_channel_unref(io_); - io_ = nullptr; - } - - if (watch_tag_) { - g_source_remove(watch_tag_); - watch_tag_ = 0; - } -} - -gboolean DebugPortImpl::OnDebugPortDisconnectedCb(GIOChannel* io, - GIOCondition cond, gpointer data) { - _W("cond(%d)", static_cast(cond)); - auto* debug_port = static_cast(data); - std::lock_guard lock(debug_port->GetMutex()); - debug_port->SetConnectionStatus(false); - debug_port->watch_tag_ = 0; - debug_port->Unwatch(); - debug_port->port_.reset(); - _W("Disconnected"); - return G_SOURCE_REMOVE; -} - -void DebugPortImpl::SetConnectionStatus(bool status) { - connected_.exchange(status); -} - -void DebugPortImpl::CreateThread() { - if (is_running_) - return; - - thread_ = std::thread([&]() { - _W("START"); - do { - std::shared_ptr parcel = queue_.WaitAndPop(); - int len = parcel->GetDataSize(); - if (len == 0) { - _W("Done"); - break; - } - - if (!IsConnected()) - continue; - - int ret = port_->Write(reinterpret_cast(&len), sizeof(len)); - if (ret < 0) { - _E("Failed to write size"); - SetConnectionStatus(false); - continue; - } - - ret = port_->Write(parcel->GetData(), len); - if (ret < 0) { - _E("Failed to write data"); - SetConnectionStatus(false); - } - } while (true); - _W("END"); - }); - - is_running_ = true; -} - -void DebugPortImpl::JoinThread() { - if (is_running_) - queue_.Push(std::shared_ptr(new tizen_base::Parcel())); - - if (thread_.joinable()) { - _W("Join thread"); - thread_.join(); - } -} - - -std::recursive_mutex& DebugPortImpl::GetMutex() const { - return mutex_; -} - -int DebugPortImpl::AppComCb(const char* endpoint, aul_app_com_result_e result, - bundle* envelope, void* user_data) { - const char* val = bundle_get_val(envelope, KEY_PORT_NAME); - if (val == nullptr) - return -1; - - auto* handle = static_cast(user_data); - std::string port_name(val); - if (port_name.empty() || handle->FindSession(port_name) != nullptr) { - auto* handle = static_cast(user_data); - int fd = handle->Connect(); - if (fd < 0) - return -1; - - std::lock_guard lock(handle->GetMutex()); - handle->port_.reset(new Port(fd, "Debug")); - int ret = handle->Watch(fd); - if (ret < 0) - return -1; - - handle->SetConnectionStatus(true); - _W("Connected"); - handle->CreateThread(); - } - - return 0; -} - -DebugPortImpl impl; - -} // namespace - -bool DebugPort::IsConnected() { - impl.Init(); - return impl.IsConnected(); -} - -void DebugPort::AddSession(std::string port_name, std::string destination, - int main_port, int delegate_port) { - impl.Init(); - return impl.AddSession(std::move(port_name), std::move(destination), - main_port, delegate_port); -} - -void DebugPort::RemoveSession(int port) { - impl.Init(); - return impl.RemoveSession(port); -} - -int DebugPort::Send(int port, bool is_read, uint32_t seq, const void* buf, - unsigned int size) { - impl.Init(); - return impl.Send(port, is_read, seq, buf, size); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/debug-port-internal.hh b/src/debug-port-internal.hh deleted file mode 100644 index 9b68c65..0000000 --- a/src/debug-port-internal.hh +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef DEBUG_PORT_INTERNAL_HH_ -#define DEBUG_PORT_INTERNAL_HH_ - -#include -#include - -namespace rpc_port { -namespace internal { - -class DebugPort { - public: - static bool IsConnected(); - static void AddSession(std::string port_name, std::string destination, - int main_port, int delegate_port); - static void RemoveSession(int port); - static int Send(int port, bool is_read, uint32_t seq, - const void* buf, unsigned int size); -}; - -} // namespace internal -} // namespace rpc_port - -#endif // DEBUG_PORT_INTERNAL_HH_ diff --git a/src/exception-internal.cc b/src/exception-internal.cc deleted file mode 100644 index 51a7bb9..0000000 --- a/src/exception-internal.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 "exception-internal.hh" - -#include - -namespace rpc_port { -namespace internal { - -// LCOV_EXCL_START -Exception::Exception(int error_code, const std::string& file, int line) - : error_code_(error_code), - message_(std::move(GetErrorMessage(error_code_, file, line))) { -} - -const char* Exception::what() const noexcept { - return message_.c_str(); -} - -int Exception::GetErrorCode() { - return error_code_; -} - -std::string Exception::GetErrorMessage(int error_code, const std::string& file, - int line) { - return file.substr(file.find_last_of("/") + 1) + ":" + std::to_string(line) + - " error_code: " + std::to_string(error_code); -} -// LCOV_EXCL_STOP - -} // namespace internal -} // namespace rpc_port diff --git a/src/exception-internal.hh b/src/exception-internal.hh deleted file mode 100644 index 226c909..0000000 --- a/src/exception-internal.hh +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef EXCEPTION_INTERNAL_HH_ -#define EXCEPTION_INTERNAL_HH_ - -#include -#include - -#define THROW(error_code) throw Exception(error_code, __FUNCTION__, __LINE__) - -namespace rpc_port { -namespace internal { - -class Exception : public std::exception { - public: - explicit Exception(int error_code, const std::string& file, int line); - virtual ~Exception() = default; // LCOV_EXCL_LINE - - virtual const char* what() const noexcept; - int GetErrorCode(); - - private: - static std::string GetErrorMessage(int error_code, const std::string& file, - int line); - - private: - int error_code_; - std::string message_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // EXCEPTION_INTERNAL_HH_ diff --git a/src/file-monitor-internal.cc b/src/file-monitor-internal.cc deleted file mode 100644 index f8b0303..0000000 --- a/src/file-monitor-internal.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. - * - * 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 "file-monitor-internal.hh" - -#include -#include -#include - -#include -#include - -#include "exception-internal.hh" -#include "log-private.hh" - -namespace rpc_port { -namespace internal { -namespace fs = std::filesystem; - -FileMonitor::FileMonitor(std::string path, IEvent* listener) - : path_(std::move(path)), listener_(listener) { - const auto fs_path = fs::path(path_); - parent_path_ = fs_path.parent_path().string(); - file_name_ = fs_path.filename().string(); - _W("path=%s, parent_path=%s, file_name=%s", - path_.c_str(), parent_path_.c_str(), file_name_.c_str()); -} - -FileMonitor::~FileMonitor() { - _W("path=%s", path_.c_str()); - Stop(); -} - -bool FileMonitor::Exist() { - if (access(path_.c_str(), F_OK) == 0) return true; - - return false; -} - -void FileMonitor::Start() { - fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (fd_ < 0) { - _E("inotify_init1() is failed. errno(%d)", errno); - THROW(-1); - } - - wd_ = inotify_add_watch(fd_, parent_path_.c_str(), IN_CREATE | IN_DELETE); - if (wd_ < 0) { - _E("inotify_add_watch() is failed. errno(%d)", errno); - Stop(); - THROW(-1); - } - - channel_ = g_io_channel_unix_new(fd_); - if (channel_ == nullptr) { - _E("g_io_channel_unix_new() is failed"); - Stop(); - THROW(-1); - } - - source_ = g_io_create_watch(channel_, G_IO_IN); - if (source_ == nullptr) { - _E("g_io_create_watch() is failed"); - Stop(); - THROW(-1); - } - - g_source_set_callback(source_, reinterpret_cast(GIOFunc), this, - nullptr); - g_source_attach(source_, nullptr); - g_source_unref(source_); -} - -void FileMonitor::Stop() { - if (source_ && !g_source_is_destroyed(source_)) { - g_source_destroy(source_); - source_ = nullptr; - } - - if (channel_) { - g_io_channel_unref(channel_); - channel_ = nullptr; - } - - if (wd_ > -1) { - inotify_rm_watch(fd_, wd_); - wd_ = -1; - } - - if (fd_ > -1) { - close(fd_); - fd_ = -1; - } -} - -gboolean FileMonitor::GIOFunc(GIOChannel* channel, GIOCondition condition, - gpointer user_data) { - char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); - auto* monitor = static_cast(user_data); - auto* listener = monitor->listener_; - int fd = g_io_channel_unix_get_fd(channel); - struct inotify_event* event; - ssize_t len; - char* ptr; - char* nptr; - - while ((len = read(fd, buf, sizeof(buf))) > 0) { - for (ptr = buf; ptr < buf + len; - ptr += sizeof(struct inotify_event) + event->len) { - event = reinterpret_cast(ptr); - nptr = ptr + sizeof(struct inotify_event) + event->len; - if (nptr > buf + len) break; - - if (monitor->file_name_ != event->name) continue; - - if (event->mask & IN_CREATE) { - listener->OnFileCreated(monitor->path_); - return G_SOURCE_CONTINUE; - } - - if (event->mask & IN_DELETE) - listener->OnFileDeleted(monitor->path_); - } - } - - return G_SOURCE_CONTINUE; -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/file-monitor-internal.hh b/src/file-monitor-internal.hh deleted file mode 100644 index 2058402..0000000 --- a/src/file-monitor-internal.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef FILE_MONITOR_INTERNAL_HH_ -#define FILE_MONITOR_INTERNAL_HH_ - -#include -#include - -#include - -namespace rpc_port { -namespace internal { - -class FileMonitor { - public: - class IEvent { - public: - virtual ~IEvent() = default; - virtual void OnFileCreated(const std::string& path) = 0; - virtual void OnFileDeleted(const std::string& path) = 0; - }; - - explicit FileMonitor(std::string path, IEvent* listener = nullptr); - ~FileMonitor(); - - void Start(); - void Stop(); - bool Exist(); - - private: - static gboolean GIOFunc(GIOChannel* channel, GIOCondition condition, - gpointer user_data); - - private: - std::string path_; - std::string parent_path_; - std::string file_name_; - IEvent* listener_ = nullptr; - int fd_ = -1; - int wd_ = -1; - GIOChannel* channel_ = nullptr; - GSource* source_ = nullptr; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // FILE_MONITOR_INTERNAL_HH_ diff --git a/src/log-private.hh b/src/log-private.hh deleted file mode 100644 index 36aeb9c..0000000 --- a/src/log-private.hh +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef LOG_PRIVATE_HH_ -#define LOG_PRIVATE_HH_ - -#include - -#undef LOG_TAG -#define LOG_TAG "RPC_PORT" - -#undef _E -#define _E LOGE - -#undef _W -#define _W LOGW - -#undef _I -#define _I LOGI - -#undef _D -#define _D LOGD - -#endif // LOG_PRIVATE_HH_ diff --git a/src/message-sending-thread-internal.cc b/src/message-sending-thread-internal.cc deleted file mode 100644 index b21eddd..0000000 --- a/src/message-sending-thread-internal.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 "log-private.hh" -#include "message-sending-thread-internal.hh" - -namespace rpc_port { -namespace internal { - -// LCOV_EXCL_START -MessageSendingThread& MessageSendingThread::GetInst() { - static MessageSendingThread inst; - return inst; -} - -MessageSendingThread::MessageSendingThread() { - context_ = g_main_context_new(); - loop_ = g_main_loop_new(context_, false); - std::unique_lock lock(mutex_); - thread_ = std::make_unique([&]() -> void { ThreadLoop(); }); - cond_.wait(lock, [&] { return thread_ok_; }); -} - -MessageSendingThread::~MessageSendingThread() { - Dispose(); -} - -gboolean MessageSendingThread::NotifyOne(gpointer data) { - auto* sender = static_cast(data); - std::unique_lock lock(sender->mutex_); - sender->thread_ok_ = true; - sender->cond_.notify_one(); - return G_SOURCE_REMOVE; -} - -void MessageSendingThread::ThreadLoop() { - { - std::unique_lock lock(mutex_); - GSource* source = g_idle_source_new(); - if (source == nullptr) { - _E("Failed to create GSource"); - cond_.notify_one(); - return; - } - - g_source_set_callback(source, NotifyOne, this, nullptr); - g_source_set_priority(source, G_PRIORITY_HIGH); - g_source_attach(source, context_); - g_source_unref(source); - - g_main_context_push_thread_default(context_); - } - - g_main_loop_run(loop_); - - g_main_context_pop_thread_default(context_); - _W("Shutdown message sending thread"); -} - -void MessageSendingThread::Dispose() { - std::unique_lock lock(mutex_); - if (g_main_loop_is_running(loop_)) - g_main_loop_quit(loop_); - else - _E("GMainLoop is not running"); - - thread_->join(); - - g_main_loop_unref(loop_); - loop_ = nullptr; - - g_main_context_unref(context_); - context_ = nullptr; -} - -GMainContext* MessageSendingThread::GetContext() { - return context_; -} -// LCOV_EXCL_STOP - -} // namespace internal -} // namespace rpc_port - diff --git a/src/message-sending-thread-internal.hh b/src/message-sending-thread-internal.hh deleted file mode 100644 index 1d3acad..0000000 --- a/src/message-sending-thread-internal.hh +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef MESSAGE_SENDING_THREAD_INTERNAL_HH_ -#define MESSAGE_SENDING_THREAD_INTERNAL_HH_ - -#include -#include - -#include -#include -#include -#include -#include - -#include "port-internal.hh" - -namespace rpc_port { -namespace internal { - -class MessageSendingThread { - public: - static MessageSendingThread& GetInst(); - ~MessageSendingThread(); - GMainContext* GetContext(); - - private: - MessageSendingThread(); - void ThreadLoop(); - void Dispose(); - static gboolean NotifyOne(gpointer data); - - GMainContext* context_ = nullptr; - GMainLoop* loop_ = nullptr; - bool thread_ok_ = false; - std::unique_ptr thread_; - std::mutex mutex_; - std::condition_variable cond_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // MESSAGE_SENDING_THREAD_INTERNAL_HH_ diff --git a/src/parcel-header-internal.cc b/src/parcel-header-internal.cc deleted file mode 100644 index f4413dd..0000000 --- a/src/parcel-header-internal.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 -#include -#include -#include - -#include "parcel-header-internal.hh" - -namespace rpc_port { -namespace internal { - -ParcelHeader::ParcelHeader() : seq_num_(GenerateSeqNum()) { - clock_gettime(CLOCK_MONOTONIC_RAW, &time_stamp_); -} - -void ParcelHeader::WriteToParcel(tizen_base::Parcel* parcel) const { - parcel->WriteString(tag_); - parcel->WriteInt32(seq_num_); - parcel->WriteInt64(static_cast(time_stamp_.tv_sec)); - parcel->WriteInt64(static_cast(time_stamp_.tv_nsec)); -} - -void ParcelHeader::ReadFromParcel(tizen_base::Parcel* parcel) { - tag_ = std::move(parcel->ReadString()); - parcel->ReadInt32(&seq_num_); - - int64_t tv_sec = 0; - parcel->ReadInt64(&tv_sec); - time_stamp_.tv_sec = tv_sec & std::numeric_limits::max(); - - int64_t tv_nsec = 0; - parcel->ReadInt64(&tv_nsec); - time_stamp_.tv_nsec = tv_nsec & std::numeric_limits::max(); -} - -void ParcelHeader::SetTag(std::string tag) { - tag_ = std::move(tag); -} - -const std::string& ParcelHeader::GetTag() const { - return tag_; -} - -void ParcelHeader::SetSeqNum(int seq_num) { - seq_num_ = seq_num; -} - -int ParcelHeader::GetSeqNum() const { - return seq_num_; -} - -struct timespec ParcelHeader::GetTimeStamp() const { - return time_stamp_; -} - -int ParcelHeader::GenerateSeqNum() { - static std::atomic num { 0 }; - ++num; - return static_cast(num & INT_MAX); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/parcel-header-internal.hh b/src/parcel-header-internal.hh deleted file mode 100644 index 32a9007..0000000 --- a/src/parcel-header-internal.hh +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef PARCEL_HEADER_INTERNAL_H_ -#define PARCEL_HEADER_INTERNAL_H_ - -#include - -#include - -#include - -namespace rpc_port { -namespace internal { - -class ParcelHeader : public tizen_base::Parcelable { - public: - ParcelHeader(); - - void WriteToParcel(tizen_base::Parcel* parcel) const override; - void ReadFromParcel(tizen_base::Parcel* parcel) override; - - void SetTag(std::string tag); - const std::string& GetTag() const; - void SetSeqNum(int seq_num); - int GetSeqNum() const; - struct timespec GetTimeStamp() const; - - static int GenerateSeqNum(); - - private: - std::string tag_; - int seq_num_; - struct timespec time_stamp_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // PARCEL_HEADER_INTERNAL_H_ diff --git a/src/parcel-internal.cc b/src/parcel-internal.cc deleted file mode 100644 index 932569c..0000000 --- a/src/parcel-internal.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 "parcel-internal.hh" - -#include -#include - -#include "log-private.hh" - -namespace rpc_port { -namespace internal { - -Parcel::Parcel(bool without_header) - : header_(without_header ? nullptr : new ParcelHeader()) { -} - -Parcel::~Parcel() {} - -void Parcel::WriteToParcel(tizen_base::Parcel* parcel) const { - if (header_.get() != nullptr) { - parcel->WriteParcelable(*header_.get()); - parcel->WriteUInt32(handle_.GetDataSize()); - } - - parcel->Write(handle_.GetData(), handle_.GetDataSize()); -} - -void Parcel::ReadFromParcel(tizen_base::Parcel* parcel) { - if (header_.get() != nullptr) { - parcel->ReadParcelable(header_.get()); - - uint32_t size = 0; - parcel->ReadUInt32(&size); - if (size > 0) { - auto* buf = static_cast(malloc(size)); - if (buf == nullptr) { - _E("Out of memory"); // LCOV_EXEC_LINE - return; // LCOV_EXCL_LINE - } - - parcel->Read(buf, size); - handle_ = std::move(tizen_base::Parcel(buf, size, false)); - } - } else { - // LCOV_EXCL_START - handle_ = std::move( - tizen_base::Parcel(parcel->GetData(), parcel->GetDataSize())); - // LCOV_EXCL_STOP - } -} - -const ParcelHeader* Parcel::GetParcelHeader() { - return header_.get(); -} - -parcel_h Parcel::GetHandle() const { - return static_cast(const_cast(&handle_)); -} - -void Parcel::SetRawParcel(tizen_base::Parcel* raw_parcel) { - raw_parcel_.reset(raw_parcel); -} - -// LCOV_EXCL_START -tizen_base::Parcel* Parcel::GetRawParcel() const { - return raw_parcel_.get(); -} -// LCOV_EXCL_STOP - -} // namespace internal -} // namespace rpc_port diff --git a/src/parcel-internal.hh b/src/parcel-internal.hh deleted file mode 100644 index 3d0911d..0000000 --- a/src/parcel-internal.hh +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef PARCEL_INTERNAL_HH_ -#define PARCEL_INTERNAL_HH_ - -#include - -#include -#include - -#include - -#include "parcel-header-internal.hh" - -namespace rpc_port { -namespace internal { - -class Parcel : public tizen_base::Parcelable { - public: - Parcel(bool without_header = false); - ~Parcel(); - - void WriteToParcel(tizen_base::Parcel* parcel) const override; - void ReadFromParcel(tizen_base::Parcel* parcel) override; - - const ParcelHeader* GetParcelHeader(); - parcel_h GetHandle() const; - - void SetRawParcel(tizen_base::Parcel* raw_parcel); - tizen_base::Parcel* GetRawParcel() const; - - private: - std::unique_ptr header_; - tizen_base::Parcel handle_; - std::unique_ptr raw_parcel_ { nullptr }; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // PARCEL_INTERNAL_HH_ diff --git a/src/peer-cred-internal.cc b/src/peer-cred-internal.cc deleted file mode 100644 index 150d3ab..0000000 --- a/src/peer-cred-internal.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 -#include - -#include - -#include "log-private.hh" -#include "peer-cred-internal.hh" - -namespace rpc_port { -namespace internal { - -PeerCred::PeerCred(pid_t pid, uid_t uid, gid_t gid) - : pid_(pid), uid_(uid), gid_(gid) { -} - -PeerCred* PeerCred::Get(int fd) { - struct ucred cred; - socklen_t len = static_cast(sizeof(struct ucred)); - int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, - static_cast(&cred), &len); - if (ret != 0) { - _E("getsockopt() is failed. fd(%d), errno(%d)", fd, errno); // LCOV_EXCL_LINE - return nullptr; // LCOV_EXCL_LINE - } - - return new (std::nothrow) PeerCred(cred.pid, cred.uid, cred.gid); -} - -pid_t PeerCred::GetPid() const { - return pid_; -} - -uid_t PeerCred::GetUid() const { - return uid_; -} - - -// LCOV_EXCL_START -gid_t PeerCred::GetGid() const { - return gid_; -} -// LCOV_EXCL_STOP - -} // namespace internal -} // namespace rpc_port diff --git a/src/peer-cred-internal.hh b/src/peer-cred-internal.hh deleted file mode 100644 index bf57ed5..0000000 --- a/src/peer-cred-internal.hh +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef PEER_CRED_INTERNAL_HH_ -#define PEER_CRED_INTERNAL_HH_ - -namespace rpc_port { -namespace internal { - -class PeerCred { - public: - static PeerCred* Get(int fd); - - pid_t GetPid() const; - uid_t GetUid() const; - gid_t GetGid() const; - - private: - PeerCred(pid_t pid, uid_t uid, gid_t gid); - - private: - pid_t pid_; - uid_t uid_; - gid_t gid_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // PEER_CRED_INTERNAL_HH_ diff --git a/src/port-internal.cc b/src/port-internal.cc deleted file mode 100644 index c32d5fb..0000000 --- a/src/port-internal.cc +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "include/rpc-port.h" -#include "log-private.hh" -#include "message-sending-thread-internal.hh" -#include "port-internal.hh" - -namespace rpc_port { -namespace internal { -namespace { - -constexpr const int QUEUE_SIZE_MAX = 1024 * 1024 * 10; -constexpr const int MAX_RETRY_CNT = 10; -constexpr const int MAX_TIMEOUT = 1000; -constexpr const int MIN_TIMEOUT = 50; - -} // namespace - -// LCOV_EXCL_START -Port::DelayMessage::DelayMessage(const char* msg, int index, int size) - : message_(msg, msg + size), index_(index), size_(size) { -} - -void Port::DelayMessage::SetIndex(int index) { - index_ += index; -} - -int Port::DelayMessage::GetSize() { - return size_ - index_; -} - -int Port::DelayMessage::GetOriginalSize() { - return size_; -} - -char* Port::DelayMessage::GetMessage() { - char* ptr = reinterpret_cast(message_.data()); - ptr += index_; - return ptr; -} -// LCOV_EXCL_STOP - -Port::Port(int fd, std::string id) - : fd_(fd), id_(std::move(id)), instance_(""), seq_(0) { - char uuid[37]; - uuid_t u; - uuid_generate(u); - uuid_unparse(u, uuid); - instance_ = std::string(uuid) + ":" + id_; - SetReceiveTimeout(10000); -} - -Port::Port(int fd, std::string id, std::string instance) - : fd_(fd), id_(std::move(id)), instance_(std::move(instance)), seq_(0) { - SetReceiveTimeout(10000); -} - -Port::~Port() { - std::lock_guard lock(mutex_); - ClearQueue(); - Disconnect(); -} - -void Port::Disconnect() { - IgnoreIOEvent(); - - std::lock_guard lock(rw_mutex_); - if (fd_ > 0) { - _W("Close fd(%d)", fd_); - close(fd_); - fd_ = -1; - } -} - -int Port::SetPrivateSharing(const char* paths[], unsigned int size) { - int ret = aul_rpc_port_set_private_sharing(id_.c_str(), paths, size); - if (ret != 0) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -int Port::SetPrivateSharing(const char* path) { - const char* file_list[1] = {path}; - int ret = aul_rpc_port_set_private_sharing(id_.c_str(), file_list, 1); - if (ret != 0) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - return RPC_PORT_ERROR_NONE; -} - -int Port::UnsetPrivateSharing() { - int ret = aul_rpc_port_unset_private_sharing(id_.c_str()); - if (ret != 0) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - return RPC_PORT_ERROR_NONE; -} - -int Port::Read(void* buf, unsigned int size) { - unsigned int left = size; - ssize_t nb; - int bytes_read = 0; - char* buffer = static_cast(buf); - int flags; - - std::lock_guard lock(rw_mutex_); - if (fd_ < 0 || fd_ >= sysconf(_SC_OPEN_MAX)) { - _E("Invalid fd(%d)", fd_); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - flags = fcntl(fd_, F_GETFL, 0); - fcntl(fd_, F_SETFL, flags & ~O_NONBLOCK); - - while (left) { - nb = read(fd_, buffer, left); - if (nb == 0) { - _E("read_socket: ...read EOF, socket closed %d: nb %zd\n", fd_, nb); - fcntl(fd_, F_SETFL, flags); - return RPC_PORT_ERROR_IO_ERROR; - } - - if (nb == -1) { - if (errno == EINTR) { - usleep(100 * 1000); - continue; - } - - _E("read_socket: ...error fd %d: errno %d\n", fd_, errno); - fcntl(fd_, F_SETFL, flags); - return RPC_PORT_ERROR_IO_ERROR; - } - - left -= nb; - buffer += nb; - bytes_read += nb; - } - - fcntl(fd_, F_SETFL, flags); - return RPC_PORT_ERROR_NONE; -} - -// LCOV_EXCL_START -int Port::SetReceiveTimeout(int timeout) { - if (timeout == INT_MAX) - return -EINVAL; - - if (timeout == -1) - timeout = 10000; - - if (timeout < 0) { - _E("Invalid parameter"); - return -EINVAL; - } - - struct timeval tv = { - .tv_sec = static_cast(timeout / 1000), - .tv_usec = static_cast((timeout % 1000) * 1000) - }; - socklen_t len = static_cast(sizeof(struct timeval)); - int ret = setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &tv, len); - if (ret < 0) { - ret = -errno; - _E("setsockopt() is failed. errno(%d)", errno); - } - - return ret; -} - -bool Port::CanWrite() { - struct pollfd fds[1]; - fds[0].fd = fd_; - fds[0].events = POLLOUT; - fds[0].revents = 0; - int ret = poll(fds, 1, 100); - if (ret <= 0) { - _W("poll() is failed. fd(%d), error(%s)", - fd_, ret == 0 ? "timed out" : std::to_string(-errno).c_str()); - return false; - } - - return true; -} -// LCOV_EXCL_STOP - -int Port::Write(const void* buf, unsigned int size) { - int sent_bytes = 0; - int ret; - std::lock_guard lock(rw_mutex_); - - if (queue_.empty()) { - ret = Write(buf, size, &sent_bytes); - if (ret == PORT_STATUS_ERROR_NONE) - return RPC_PORT_ERROR_NONE; - else if (ret == PORT_STATUS_ERROR_IO_ERROR) - return RPC_PORT_ERROR_IO_ERROR; - } else if (CanWrite()) { // LCOV_EXCL_LINE - // LCOV_EXCL_START - while (!queue_.empty()) { - int port_status = PopDelayedMessage(); - if (port_status != PORT_STATUS_ERROR_NONE) { - if (port_status == PORT_STATUS_ERROR_IO_ERROR) - return RPC_PORT_ERROR_IO_ERROR; - - break; - } - } - // LCOV_EXCL_STOP - } - - // LCOV_EXCL_START - if (delayed_message_size_ > QUEUE_SIZE_MAX) { - _E("cache fail : delayed_message_size (%d), count(%zu)", - delayed_message_size_, queue_.size()); - return RPC_PORT_ERROR_IO_ERROR; - } - - return PushDelayedMessage( - std::make_shared( - static_cast(buf), sent_bytes, size)); - // LCOV_EXCL_STOP -} - -int Port::Write(const void* buf, unsigned int size, int* sent_bytes) { - unsigned int left = size; - ssize_t nb; - int retry_cnt = 0; - const char* buffer = static_cast(buf); - - if (fd_ < 0 || fd_ >= sysconf(_SC_OPEN_MAX)) { - _E("Invalid fd(%d)", fd_); // LCOV_EXCL_LINE - return PORT_STATUS_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - while (left && (retry_cnt < MAX_RETRY_CNT)) { - nb = send(fd_, buffer, left, MSG_NOSIGNAL); - if (nb == -1) { - if (errno == EINTR) { - // LCOV_EXCL_START - LOGI("write_socket: EINTR continue ..."); - retry_cnt++; - continue; - // LCOV_EXCL_STOP - } - - if (errno == EAGAIN || errno == EWOULDBLOCK) - return PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE; - - _E("write_socket: ...error fd: %d, errno: %d", fd_, errno); - return PORT_STATUS_ERROR_IO_ERROR; - } - - left -= nb; - buffer += nb; - *sent_bytes += nb; - } - - if (left != 0) { - _E("error fd %d: retry_cnt %d", fd_, retry_cnt); - return PORT_STATUS_ERROR_IO_ERROR; - } - - return PORT_STATUS_ERROR_NONE; -} - -// LCOV_EXCL_START -gboolean Port::OnEventReceived(GIOChannel* io, GIOCondition condition, - gpointer data) { - auto* ptr = static_cast*>(data); - auto port = ptr->lock(); - if (port == nullptr) { - _E("port is destructed"); - return G_SOURCE_REMOVE; - } - - _W("Writing is now possible. fd: %d, id: %s", - port->GetFd(), port->GetId().c_str()); - std::lock_guard lock(port->rw_mutex_); - if (port->source_id_ == 0) { - _E("GSource is destroyed"); - return G_SOURCE_REMOVE; - } - - if (port->queue_.empty()) { - port->IgnoreIOEvent(); - return G_SOURCE_CONTINUE; - } - - port->PopDelayedMessage(); - return G_SOURCE_CONTINUE; -} -// LCOV_EXCL_STOP - -void Port::ClearQueue() { - std::lock_guard lock(rw_mutex_); - - while (queue_.empty() == false) - queue_.pop(); - - IgnoreIOEvent(); - delayed_message_size_ = 0; -} - -void Port::IgnoreIOEvent() { - std::lock_guard lock(rw_mutex_); - if (source_id_ != 0) { - // LCOV_EXCL_START - GSource* source = g_main_context_find_source_by_id( - MessageSendingThread::GetInst().GetContext(), source_id_); - if (source != nullptr && !g_source_is_destroyed(source)) - g_source_destroy(source); - - source_id_ = 0; - // LCOV_EXCL_STOP - } - - if (channel_ != nullptr) { - g_io_channel_unref(channel_); // LCOV_EXCL_LINE - channel_ = nullptr; // LCOV_EXCL_LINE - } -} - -// LCOV_EXCL_START -int Port::ListenIOEvent() { - std::lock_guard lock(rw_mutex_); - channel_ = g_io_channel_unix_new(fd_); - if (channel_ == nullptr) { - _E("Failed to create GIOChannel"); - return RPC_PORT_ERROR_OUT_OF_MEMORY; - } - - GSource* source = g_io_create_watch(channel_, - static_cast(G_IO_OUT)); - if (source == nullptr) { - _E("Failed to create GSource"); - IgnoreIOEvent(); - return RPC_PORT_ERROR_OUT_OF_MEMORY; - } - - auto* ptr = new (std::nothrow) std::weak_ptr(shared_from_this()); - g_source_set_callback(source, reinterpret_cast(OnEventReceived), - static_cast(ptr), [](gpointer ptr) { - auto* port = static_cast*>(ptr); - delete port; - }); - g_source_set_priority(source, G_PRIORITY_DEFAULT); - source_id_ = g_source_attach(source, - MessageSendingThread::GetInst().GetContext()); - g_source_unref(source); - - return RPC_PORT_ERROR_NONE; -} - -int Port::PopDelayedMessage() { - int sent_bytes = 0; - std::lock_guard lock(rw_mutex_); - auto dm = queue_.front(); - - int ret = Write(dm->GetMessage(), dm->GetSize(), &sent_bytes); - if (ret == PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE) { - dm->SetIndex(sent_bytes); - } else if (ret == PORT_STATUS_ERROR_IO_ERROR) { - ClearQueue(); - } else { - delayed_message_size_ -= dm->GetOriginalSize(); - queue_.pop(); - } - - _W("cache : count(%zu), delayed_message_size(%d), ret(%d), sent_bytes(%d)", - queue_.size(), delayed_message_size_, ret, sent_bytes); - return ret; -} - -int Port::PushDelayedMessage(std::shared_ptr dm) { - std::lock_guard lock(rw_mutex_); - if (queue_.empty()) { - int ret = ListenIOEvent(); - if (ret != RPC_PORT_ERROR_NONE) - return ret; - } - - delayed_message_size_ += dm->GetOriginalSize(); - queue_.push(dm); - - _W("cache : count(%zu), delayed_message_size(%d)", - queue_.size(), delayed_message_size_); - return RPC_PORT_ERROR_NONE; -} -// LCOV_EXCL_STOP - -} // namespace internal -} // namespace rpc_port diff --git a/src/port-internal.hh b/src/port-internal.hh deleted file mode 100644 index 64d33ec..0000000 --- a/src/port-internal.hh +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef PORT_INTERNAL_HH_ -#define PORT_INTERNAL_HH_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rpc_port { -namespace internal { - -class Port : public std::enable_shared_from_this { - public: - Port(int fd, std::string id, std::string instance); - Port(int fd, std::string id); - virtual ~Port(); - - void Disconnect(); - int SetPrivateSharing(const char* paths[], unsigned int size); - int SetPrivateSharing(const char* path); - int UnsetPrivateSharing(); - - int Read(void* buf, unsigned int size); - int Write(const void* buf, unsigned int size); - int Write(const void* buf, unsigned int size, int* sent_bytes); - int GetFd() const { - return fd_; - } - - const std::string& GetId() const { - return id_; - } - - std::recursive_mutex& GetMutex() const { - return mutex_; - } - - const std::string& GetInstance() const { - return instance_; - } - - uint32_t GetSeq() { - return ++seq_; - } - - private: - // LCOV_EXCL_START - int SetReceiveTimeout(int timeout); - bool CanWrite(); - void IgnoreIOEvent(); - int ListenIOEvent(); - - class DelayMessage { - public: - DelayMessage(const char* msg, int start_index, int size); - ~DelayMessage() = default; - void SetIndex(int index); - int GetSize(); - int GetOriginalSize(); - char* GetMessage(); - - private: - std::vector message_; - int index_; - int size_; - }; - - enum PortStatus { - PORT_STATUS_ERROR_NONE, - PORT_STATUS_ERROR_IO_ERROR, - PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE - }; - - int PushDelayedMessage(std::shared_ptr dm); - int PopDelayedMessage(); - static gboolean OnEventReceived(GIOChannel* io, - GIOCondition condition, gpointer data); - void ClearQueue(); - // LCOV_EXCL_STOP - - int fd_; - std::string id_; - std::string instance_; - std::atomic seq_; - mutable std::recursive_mutex mutex_; - mutable std::recursive_mutex rw_mutex_; - std::queue> queue_; - int delayed_message_size_ = 0; - GIOChannel* channel_ = nullptr; - guint source_id_ = 0; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // PORT_INTERNAL_HH_ diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc deleted file mode 100644 index cd52cd6..0000000 --- a/src/proxy-internal.cc +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 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 -#include -#include -#include -#include - -#include -#include -#include - -#include "aul-internal.hh" -#include "debug-port-internal.hh" -#include "exception-internal.hh" -#include "include/rpc-port-internal.h" -#include "log-private.hh" -#include "proxy-internal.hh" -#include "request-internal.hh" -#include "response-internal.hh" - -#define EILLEGALACCESS 127 - -namespace rpc_port { -namespace internal { -namespace { - -constexpr const char kPortTypeMain[] = "main"; -constexpr const char kPortTypeDelegate[] = "delegate"; -constexpr const char kDPrefix[] = "d::"; -constexpr const char kUdPrefix[] = "ud::"; - -std::string GenInstance() { - uuid_t u; - uuid_generate(u); - char uuid[37]; - uuid_unparse(u, uuid); - return std::string(uuid) + "@" + Aul::GetAppId(getpid()); -} - -int SendRequest(ClientSocket* client, const Request& request) { - tizen_base::Parcel parcel; - parcel.WriteParcelable(const_cast(request)); - size_t size = parcel.GetDataSize(); - int ret = client->Send(reinterpret_cast(&size), sizeof(size)); - if (ret != 0) { - _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - ret = client->Send(parcel.GetData(), size); - if (ret != 0) { - _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -int ReceiveResponse(ClientSocket* client, Response** response) { - int flags = fcntl(client->GetFd(), F_GETFL, 0); - fcntl(client->GetFd(), F_SETFL, flags & ~O_NONBLOCK); - - size_t size = 0; - int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); - if (ret != 0) { - // LCOV_EXCL_START - _E("Receive() is failed. error(%d)", ret); - fcntl(client->GetFd(), F_SETFL, flags); - return -1; - // LCOV_EXCL_STOP - } - - uint8_t* buf = static_cast(malloc(size)); - if (buf == nullptr) { - // LCOV_EXCL_START - _E("Out of memory"); - fcntl(client->GetFd(), F_SETFL, flags); - return -1; - // LCOV_EXCL_STOP - } - - ret = client->Receive(buf, size); - if (ret != 0) { - // LCOV_EXCL_START - _E("Receive() is failed. error(%d)", ret); - free(buf); - fcntl(client->GetFd(), F_SETFL, flags); - return -1; - // LCOV_EXCL_STOP - } - - tizen_base::Parcel parcel(buf, size, false); - *response = new (std::nothrow) Response(); - if (*response == nullptr) { - // LCOV_EXCL_START - _E("Out of memory"); - fcntl(client->GetFd(), F_SETFL, flags); - return -1; - // LCOV_EXCL_STOP - } - - parcel.ReadParcelable(*response); - fcntl(client->GetFd(), F_SETFL, flags); - return 0; -} - -bool IsDaemon(const std::string& name) { - if (name.compare(0, strlen(kDPrefix), kDPrefix) == 0) return true; - - if (name.compare(0, strlen(kUdPrefix), kUdPrefix) == 0) return true; - - return false; -} - -} // namespace - -Proxy::Proxy() { - _D("Proxy::Proxy()"); -} - -Proxy::~Proxy() { - std::lock_guard lock(GetMutex()); - _D("Proxy::~Proxy()"); - if (main_port_.get() != nullptr) - DebugPort::RemoveSession(main_port_->GetFd()); // LCOV_EXCL_LINE - - listener_ = nullptr; - UnsetIdler(); - UnsetConnTimer(); - Cancel(); -} - -int Proxy::MainPortConnect(const std::string& instance, bool sync) { - std::lock_guard lock(GetMutex()); - fds_[0] = 0; - main_client_.reset(Client::Create(this, port_path_)); - if (main_client_.get() == nullptr) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - Request request(instance.c_str(), kPortTypeMain); - int ret = SendRequest(main_client_.get(), request); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - main_client_->SetNonblock(); - if (sync) { - Response* response = nullptr; - ret = ReceiveResponse(main_client_.get(), &response); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - std::unique_ptr response_auto(response); - if (response->GetResult() != 0) { - _E("Permission denied"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE - } - - fds_[0] = main_client_->RemoveFd(); - } else { - ret = main_client_->Watch(); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - return RPC_PORT_ERROR_NONE; -} - -int Proxy::DelegatePortConnect(const std::string& instance, bool sync) { - std::lock_guard lock(GetMutex()); - fds_[1] = 0; - delegate_client_.reset(Client::Create(this, port_path_)); - if (delegate_client_.get() == nullptr) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - Request request(instance.c_str(), kPortTypeDelegate); - int ret = SendRequest(delegate_client_.get(), request); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - delegate_client_->SetNonblock(); - if (sync) { - Response* response = nullptr; - ret = ReceiveResponse(delegate_client_.get(), &response); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - std::unique_ptr response_auto(response); - if (response->GetResult() != 0) { - _E("Permission denied"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE - } - - fds_[1] = delegate_client_->RemoveFd(); - } else { - ret = delegate_client_->Watch(); - if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - return RPC_PORT_ERROR_NONE; -} - -int Proxy::Connect(bool sync) { - std::lock_guard lock(GetMutex()); - std::string instance = GenInstance(); - int ret = MainPortConnect(instance, sync); - if (ret != RPC_PORT_ERROR_NONE) return ret; - - ret = DelegatePortConnect(instance, sync); - if (ret != RPC_PORT_ERROR_NONE) return ret; - - if (sync) { - main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); - delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); - DebugPort::AddSession(port_name_, target_appid_, fds_[0], fds_[1]); - listener_->OnConnected(target_appid_, main_port_.get()); - } - - return ret; -} - -int Proxy::Connect(std::string appid, std::string port_name, - IEventListener* listener) { - if (listener == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - std::lock_guard lock(GetMutex()); - if (HasRequested()) { - _D("Already requested"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE - } - - listener_ = listener; - target_appid_ = std::move(appid); - port_name_ = std::move(port_name); - SetRealAppId(target_appid_); - main_port_.reset(); - delegate_port_.reset(); - port_path_ = - Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid()); - - Cancel(); - UnsetConnTimer(); - if (!IsDaemon(real_appid_)) { - int ret = Aul::PrepareStub(real_appid_, port_name_, - rpc_port_get_target_uid()); - if (ret != RPC_PORT_ERROR_NONE) { - listener_ = nullptr; - return ret; - } - } - - if (Watch() != 0) { - listener_ = nullptr; // LCOV_EXCL_LINE - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - return RPC_PORT_ERROR_NONE; -} - -int Proxy::ConnectSync(std::string appid, std::string port_name, - IEventListener* listener) { - if (listener == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - std::lock_guard lock(GetMutex()); - if (HasRequested()) { - _D("Already requested"); - return RPC_PORT_ERROR_INVALID_PARAMETER; - } - - listener_ = listener; - target_appid_ = std::move(appid); - port_name_ = std::move(port_name); - SetRealAppId(target_appid_); - port_path_ = - Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid()); - - if (!IsDaemon(real_appid_)) { - int ret = Aul::PrepareStub(real_appid_, port_name_, - rpc_port_get_target_uid()); - if (ret != RPC_PORT_ERROR_NONE) { - listener_ = nullptr; - return ret; - } - } - - if (!WaitUntilPortCreation()) - return RPC_PORT_ERROR_IO_ERROR; - - int ret = Connect(true); - if (ret != RPC_PORT_ERROR_NONE) { - // LCOV_EXCL_START - listener_ = nullptr; - return ret; - // LCOV_EXCL_STOP - } - - return RPC_PORT_ERROR_NONE; -} - -bool Proxy::WaitUntilPortCreation() { - file_monitor_.reset(new FileMonitor(port_path_)); - int retry_count = 100; - do { - if (file_monitor_->Exist()) return true; - - usleep(100 * 1000); - retry_count--; - } while (retry_count > 0); - - if (!file_monitor_->Exist()) { - // LCOV_EXCL_START - _E("port(%s) of appid(%s) is not ready", - port_name_.c_str(), target_appid_.c_str()); - return false; - // LCOV_EXCL_STOP - } - - return true; -} - -void Proxy::DisconnectPort() { - std::lock_guard lock(GetMutex()); - if (main_port_.get() != nullptr) { - DebugPort::RemoveSession(main_port_->GetFd()); - main_port_.reset(); - } -} - -int Proxy::Watch() { - std::lock_guard lock(GetMutex()); - try { - file_monitor_.reset(new FileMonitor(port_path_, this)); - file_monitor_->Start(); - SetConnTimer(); - SetIdler(); - } catch (const Exception& e) { - LOGE("Exception occurs. error(%s)", e.what()); - return -1; - } - - return 0; -} - -void Proxy::Cancel() { - std::lock_guard lock(GetMutex()); - if (!file_monitor_) return; - - file_monitor_->Stop(); -} - -void Proxy::SetRealAppId(const std::string& alias_appid) { - std::lock_guard lock(GetMutex()); - if (!real_appid_.empty()) - return; - - if (IsDaemon(alias_appid)) { - real_appid_ = alias_appid; - return; - } - - char* appid = nullptr; - int ret = aul_svc_get_appid_by_alias_appid(alias_appid.c_str(), &appid); - if (ret != AUL_SVC_RET_OK) { - real_appid_ = alias_appid; - return; - } - - // LCOV_EXCL_START - std::unique_ptr appid_ptr(appid, std::free); - real_appid_ = std::string(appid); - _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid); - // LCOV_EXCL_STOP -} - -std::recursive_mutex& Proxy::GetMutex() const { - return mutex_; -} - -void Proxy::SetConnTimer() { - if (conn_timer_data_) { - _W("Already exists"); // LCOV_EXCL_START - return; // LCOV_EXCL_START - } - - conn_timer_data_ = CreateWeakPtr(); - if (conn_timer_data_ == nullptr) { - _E("Out of memory"); // LCOV_EXCL_START - return; // LCOV_EXCL_START - } - - g_timeout_add_seconds(10, OnTimedOut, conn_timer_data_); -} - -void Proxy::UnsetConnTimer() { - if (conn_timer_data_ == nullptr) - return; - - GSource* source = g_main_context_find_source_by_user_data(nullptr, - conn_timer_data_); - if (source && !g_source_is_destroyed(source)) - g_source_destroy(source); - - DestroyWeakPtr(conn_timer_data_); - conn_timer_data_ = nullptr; -} - -void Proxy::SetIdler() { - if (idler_data_) { - _W("Already exists"); // LCOV_EXCL_START - return; // LCOV_EXCL_START - } - - idler_data_ = CreateWeakPtr(); - if (idler_data_ == nullptr) { - _E("Out of memory"); // LCOV_EXCL_START - return; // LCOV_EXCL_START - } - - g_idle_add(OnIdle, idler_data_); -} - -void Proxy::UnsetIdler() { - if (idler_data_ == nullptr) - return; - - GSource* source = g_main_context_find_source_by_user_data(nullptr, - idler_data_); - if (source && !g_source_is_destroyed(source)) - g_source_destroy(source); - - DestroyWeakPtr(idler_data_); - idler_data_ = nullptr; -} - -void Proxy::OnFileCreated(const std::string& path) { - _W("appid=%s, port_name=%s, port_path=%s", - target_appid_.c_str(), port_name_.c_str(), path.c_str()); - std::lock_guard lock(GetMutex()); - UnsetIdler(); - Cancel(); - if (listener_ == nullptr) return; // LCOV_EXCL_LINE - - int ret = Connect(false); - if (ret != RPC_PORT_ERROR_NONE) { - // LCOV_EXCL_START - UnsetConnTimer(); - auto* listener = listener_; - listener_ = nullptr; - if (ret == RPC_PORT_ERROR_PERMISSION_DENIED) - listener->OnRejected(target_appid_, ret); - else - listener->OnDisconnected(target_appid_); - // LCOV_EXCL_STOP - } -} - -void Proxy::OnFileDeleted(const std::string& path) { - _W("appid=%s, port_name=%s, port_path=%s", - target_appid_.c_str(), port_name_.c_str(), path.c_str()); - std::lock_guard lock(GetMutex()); - UnsetIdler(); -} - -gboolean Proxy::OnTimedOut(gpointer user_data) { - _E("Timed out"); - auto* ptr = static_cast*>(user_data); - auto proxy = ptr->lock(); - if (proxy == nullptr) { - _E("Proxy is nullptr"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - std::lock_guard lock(proxy->GetMutex()); - if (proxy->conn_timer_data_ == nullptr) { - _E("Invalid context. proxy(%p)", proxy.get()); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - proxy->Cancel(); - proxy->main_client_.reset(); - proxy->delegate_client_.reset(); - DestroyWeakPtr(proxy->conn_timer_data_); - proxy->conn_timer_data_ = nullptr; - - auto* listener = proxy->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - proxy->listener_ = nullptr; - listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); - return G_SOURCE_REMOVE; -} - -gboolean Proxy::OnIdle(gpointer user_data) { - auto* ptr = static_cast*>(user_data); - auto proxy = ptr->lock(); - if (proxy == nullptr) { - _E("Proxy is nullptr"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - std::lock_guard lock(proxy->GetMutex()); - if (proxy->idler_data_ == nullptr) { - _E("Invalid context. proxy(%p)", proxy.get()); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - DestroyWeakPtr(proxy->idler_data_); - proxy->idler_data_ = nullptr; - - if (proxy->file_monitor_->Exist()) { - proxy->OnFileCreated(proxy->port_path_); - } else { - proxy->OnFileDeleted(proxy->port_path_); - } - - return G_SOURCE_REMOVE; -} - -Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, - bool receive) - : Port(fd, id), parent_(parent) { - Watch(receive); -} - -Proxy::ProxyPort::~ProxyPort() { - if (disconn_source_ > 0) - g_source_remove(disconn_source_); - - if (source_ > 0) - g_source_remove(source_); - - if (channel_ != nullptr) - g_io_channel_unref(channel_); -} - -int Proxy::ProxyPort::Watch(bool receive) { - channel_ = g_io_channel_unix_new(GetFd()); - if (channel_ == nullptr) { - _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - disconn_source_ = g_io_add_watch(channel_, - static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), - Proxy::ProxyPort::OnSocketDisconnected, parent_); - if (disconn_source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - if (!receive) - return 0; - - source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), - Proxy::ProxyPort::OnDataReceived, parent_); - if (source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -void Proxy::ProxyPort::SetDisconnectedSource(guint source_id) { - disconn_source_ = source_id; -} - -void Proxy::ProxyPort::SetSource(guint source_id) { - source_ = source_id; -} - -gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* proxy = static_cast(user_data); - std::lock_guard lock(proxy->GetMutex()); - auto* listener = proxy->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - int fd = g_io_channel_unix_get_fd(channel); - _W("Socket was disconnected. fd(%d)", fd); - if (proxy->main_port_.get() != nullptr && - proxy->main_port_->GetFd() == fd) { - proxy->main_port_->SetDisconnectedSource(0); - } else if (proxy->delegate_port_.get() != nullptr && - proxy->delegate_port_->GetFd() == fd) { - proxy->delegate_port_->SetDisconnectedSource(0); - } - - proxy->main_port_.reset(); - proxy->delegate_port_.reset(); - proxy->listener_ = nullptr; - listener->OnDisconnected(proxy->target_appid_); - DebugPort::RemoveSession(fd); - return G_SOURCE_REMOVE; -} - -gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* proxy = static_cast(user_data); - std::lock_guard lock(proxy->GetMutex()); - auto* listener = proxy->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - int fd = g_io_channel_unix_get_fd(channel); - if (proxy->delegate_port_->GetFd() == fd) { - char buffer[4]; - if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - _W("Socket was disconnected by stub. fd(%d)", fd); - proxy->listener_ = nullptr; - proxy->delegate_port_->SetSource(0); - if (proxy->main_port_.get() != nullptr) { - DebugPort::RemoveSession(proxy->main_port_->GetFd()); - proxy->main_port_.reset(); - } - proxy->delegate_port_.reset(); - listener->OnDisconnected(proxy->target_appid_); - return G_SOURCE_REMOVE; - } - - listener->OnReceived(proxy->target_appid_); - } - - return G_SOURCE_CONTINUE; -} - -Proxy::Client::Client(Proxy* parent) : parent_(parent) { -} - -Proxy::Client::~Client() { - if (channel_) - g_io_channel_unref(channel_); - - if (disconn_source_ > 0) - g_source_remove(disconn_source_); - - if (source_ > 0) - g_source_remove(source_); -} - -Proxy::Client* Proxy::Client::Create(Proxy* parent, - const std::string& endpoint) { - std::unique_ptr client; - try { - client.reset(new (std::nothrow) Proxy::Client(parent)); - } catch (const Exception& e) { - _E("Exception(%s) occurs", e.what()); // LCOV_EXCL_LINE - return nullptr; // LCOV_EXCL_LINE - } - - int ret; - int retry_count = 5; - do { - ret = client->Connect(endpoint); - if (ret == 0) { - break; - } else if (ret < 0) { - // LCOV_EXCL_START - _D("Connect() is failed"); - usleep(100 * 1000); - retry_count--; - // LCOV_EXCL_STOP - } - } while (retry_count > 0); - - if (ret != 0) { - _E("Connect() is failed"); // LCOV_EXCL_LINE - return nullptr; // LCOV_EXCL_LINE - } - - try { - client->SetReceiveTimeout(10000); - } catch (const Exception& e) { - _E("Exception occurs. error(%s)", e.what()); // LCOV_EXCL_LINE - return nullptr; // LCOV_EXCL_LINE - } - - _W("endpoint(%s), fd(%d)", endpoint.c_str(), client->GetFd()); - return client.release(); -} - -int Proxy::Client::Watch() { - channel_ = g_io_channel_unix_new(GetFd()); - if (channel_ == nullptr) { - _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), - Proxy::Client::OnResponseReceived, parent_); - if (source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - disconn_source_ = g_io_add_watch(channel_, - static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), - Proxy::Client::OnSocketDisconnected, parent_); - if (disconn_source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -// LCOV_EXCL_START -void Proxy::Client::SetDisconnectedSource(guint source) { - disconn_source_ = source; -} -// LCOV_EXCL_STOP - -void Proxy::Client::SetSource(guint source) { - source_ = source; -} - -// LCOV_EXCL_START -gboolean Proxy::Client::OnSocketDisconnected(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* proxy = static_cast(user_data); - std::lock_guard lock(proxy->GetMutex()); - proxy->UnsetConnTimer(); - auto* listener = proxy->listener_; - if (listener == nullptr) { - _E("Invalid context"); - return G_SOURCE_REMOVE; - } - - int fd = g_io_channel_unix_get_fd(channel); - _W("Socket was disconnected. fd(%d)", fd); - if (proxy->main_client_.get() != nullptr && - proxy->main_client_->GetFd() == fd) { - proxy->main_client_->SetDisconnectedSource(0); - } else if (proxy->delegate_client_.get() != nullptr && - proxy->delegate_client_->GetFd() == fd) { - proxy->delegate_client_->SetDisconnectedSource(0); - } - - proxy->main_client_.reset(); - proxy->delegate_client_.reset(); - proxy->listener_ = nullptr; - listener->OnDisconnected(proxy->target_appid_); - return G_SOURCE_REMOVE; -} -// LCOV_EXCL_STOP - -gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* proxy = static_cast(user_data); - std::lock_guard lock(proxy->GetMutex()); - proxy->UnsetConnTimer(); - auto* listener = proxy->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - bool is_delegate = false; - std::unique_ptr client; - int fd = g_io_channel_unix_get_fd(channel); - if (proxy->main_client_.get() != nullptr && - proxy->main_client_->GetFd() == fd) { - client.reset(proxy->main_client_.release()); - } else if (proxy->delegate_client_.get() != nullptr && - proxy->delegate_client_->GetFd() == fd) { - client.reset(proxy->delegate_client_.release()); - is_delegate = true; - } - - if (client.get() == nullptr) { - _E("Unknown fd(%d)", fd); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - client->SetSource(0); - - Response* response = nullptr; - int ret = ReceiveResponse(client.get(), &response); - if (ret != 0) { - // LCOV_EXCL_START - proxy->listener_ = nullptr; - proxy->main_client_.reset(); - proxy->delegate_client_.reset(); - listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); - return G_SOURCE_REMOVE; - // LCOV_EXCL_STOP - } - - std::unique_ptr response_auto(response); - if (response->GetResult() != 0) { - _E("Permission denied"); - proxy->listener_ = nullptr; - proxy->main_client_.reset(); - proxy->delegate_client_.reset(); - listener->OnRejected(proxy->target_appid_, - RPC_PORT_ERROR_PERMISSION_DENIED); - return G_SOURCE_REMOVE; - } - - client->SetNonblock(); - int client_fd = client->RemoveFd(); - if (is_delegate) { - _W("[DELEGATE] Result received"); - proxy->fds_[1] = client_fd; - proxy->delegate_port_.reset( - new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_)); - } else { - _W("[MAIN] Result received"); - proxy->fds_[0] = client_fd; - proxy->main_port_.reset( - new ProxyPort(proxy, proxy->fds_[0], proxy->target_appid_, false)); - } - - if (proxy->main_port_.get() != nullptr && - proxy->delegate_port_.get() != nullptr) { - _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)", - proxy->target_appid_.c_str(), proxy->port_name_.c_str(), - proxy->fds_[0], proxy->fds_[1]); - - DebugPort::AddSession(proxy->port_name_, proxy->target_appid_, - proxy->fds_[0], proxy->fds_[1]); - listener->OnConnected(proxy->target_appid_, proxy->main_port_.get()); - } - - return G_SOURCE_REMOVE; -} - -std::shared_ptr Proxy::GetSharedPtr() { - return shared_from_this(); -} - -gpointer Proxy::CreateWeakPtr() { - auto* ptr = new (std::nothrow) std::weak_ptr(GetSharedPtr()); - return static_cast(ptr); -} - -void Proxy::DestroyWeakPtr(gpointer data) { - auto* ptr = static_cast*>(data); - delete ptr; -} - -bool Proxy::HasRequested() const { - return listener_ != nullptr && - (!main_port_ || !delegate_port_ || main_port_->GetFd() > 0); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/proxy-internal.hh b/src/proxy-internal.hh deleted file mode 100644 index 2ef4dcc..0000000 --- a/src/proxy-internal.hh +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef PROXY_INTERNAL_HH_ -#define PROXY_INTERNAL_HH_ - -#include -#include -#include -#include - -#include -#include -#include - -#include "client-socket-internal.hh" -#include "file-monitor-internal.hh" -#include "port-internal.hh" - -namespace rpc_port { -namespace internal { - -class Proxy : public std::enable_shared_from_this, - public FileMonitor::IEvent { - public: - Proxy(); - virtual ~Proxy(); - - class IEventListener { - public: - virtual void OnConnected(const std::string& endpoint, Port* port) = 0; - virtual void OnDisconnected(const std::string& endpoint) = 0; - virtual void OnRejected(const std::string& endpoint, int err_code) = 0; - virtual void OnReceived(const std::string& endpoint) = 0; - }; - - int Connect(std::string appid, std::string port_name, IEventListener* ev); - int ConnectSync(std::string appid, std::string port_name, IEventListener* ev); - void DisconnectPort(); - - std::shared_ptr GetPort() const { - return main_port_; - } - - std::shared_ptr GetDelegatePort() const { - return delegate_port_; - } - - const std::string& GetPortName() { - return port_name_; - } - - private: - class ProxyPort : public Port { - public: - ProxyPort(Proxy* parent, int fd, const std::string& id, - bool receive = true); - virtual ~ProxyPort(); - void SetDisconnectedSource(guint source_id); - void SetSource(guint source_id); - - private: - int Watch(bool receive); - - static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - - private: - Proxy* parent_ = nullptr; - GIOChannel* channel_ = nullptr; - guint disconn_source_ = 0; - guint source_ = 0; - }; - - class Client : public ClientSocket { - public: - explicit Client(Proxy* parent); - virtual ~Client(); - - static Client* Create(Proxy* parent, const std::string& endpoint); - - int Watch(); - void SetDisconnectedSource(guint source); - void SetSource(guint source); - - private: - static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - static gboolean OnResponseReceived(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - - private: - Proxy* parent_; - GIOChannel* channel_ = nullptr; - guint disconn_source_ = 0; - guint source_ = 0; - }; - - private: - void OnFileCreated(const std::string& path) override; - void OnFileDeleted(const std::string& path) override; - static gboolean OnTimedOut(gpointer user_data); - static gboolean OnIdle(gpointer user_data); - - void SetRealAppId(const std::string& alias_appid); - std::recursive_mutex& GetMutex() const; - int MainPortConnect(const std::string& instance, bool sync); - int DelegatePortConnect(const std::string& instance, bool sync); - int Connect(bool sync); - bool WaitUntilPortCreation(); - int Watch(); - void Cancel(); - void SetConnTimer(); - void UnsetConnTimer(); - void SetIdler(); - void UnsetIdler(); - - std::shared_ptr GetSharedPtr(); - gpointer CreateWeakPtr(); - static void DestroyWeakPtr(gpointer data); - bool HasRequested() const; - - private: - std::string port_name_; - std::string port_path_; - std::shared_ptr main_port_; - std::shared_ptr delegate_port_; - IEventListener* listener_ = nullptr; - std::string target_appid_; - std::string real_appid_; - int fds_[2]; - std::unique_ptr main_client_; - std::unique_ptr delegate_client_; - gpointer conn_timer_data_ = nullptr; - gpointer idler_data_ = nullptr; - mutable std::recursive_mutex mutex_; - std::unique_ptr file_monitor_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // PROXY_INTERNAL_HH_ diff --git a/src/request-internal.cc b/src/request-internal.cc deleted file mode 100644 index c293c29..0000000 --- a/src/request-internal.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021 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 "request-internal.hh" - -#include - -namespace rpc_port { -namespace internal { - -Request::Request(std::string instance, std::string port_type) - : instance_(std::move(instance)), - port_type_(std::move(port_type)) { -} - -void Request::SetPortType(std::string port_type) { - port_type_ = std::move(port_type); -} - -const std::string& Request::GetInstance() { - return instance_; -} - -const std::string& Request::GetPortType() { - return port_type_; -} - -void Request::WriteToParcel(tizen_base::Parcel* parcel) const { - parcel->WriteString(instance_); - parcel->WriteString(port_type_); -} - -void Request::ReadFromParcel(tizen_base::Parcel* parcel) { - instance_ = parcel->ReadString(); - port_type_ = parcel->ReadString(); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/request-internal.hh b/src/request-internal.hh deleted file mode 100644 index 3aa9b05..0000000 --- a/src/request-internal.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef REQUEST_INTERNAL_HH_ -#define REQUEST_INTERNAL_HH_ - -#include -#include - -#include - -namespace rpc_port { -namespace internal { - -class Request : public tizen_base::Parcelable { - public: - Request(std::string instance, std::string port_type); - Request() = default; - ~Request() = default; - - void SetPortType(std::string port_type); - const std::string& GetInstance(); - const std::string& GetPortType(); - - void WriteToParcel(tizen_base::Parcel* parcel) const override; - void ReadFromParcel(tizen_base::Parcel* parcel) override; - - private: - std::string instance_; - std::string port_type_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // REQUEST_INTERNAL_HH_ diff --git a/src/response-internal.cc b/src/response-internal.cc deleted file mode 100644 index 9d32604..0000000 --- a/src/response-internal.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 "response-internal.hh" - -namespace rpc_port { -namespace internal { - -Response::Response(int result) : result_(result) { -} - -Response::Response() : result_(0) { -} - -int Response::GetResult() { - return result_; -} - -void Response::WriteToParcel(tizen_base::Parcel* parcel) const { - parcel->WriteInt32(result_); -} - -void Response::ReadFromParcel(tizen_base::Parcel* parcel) { - parcel->ReadInt32(&result_); -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/response-internal.hh b/src/response-internal.hh deleted file mode 100644 index 2c12ab2..0000000 --- a/src/response-internal.hh +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef RESPONSE_INTERNAL_HH_ -#define RESPONSE_INTERNAL_HH_ - -#include -#include - -namespace rpc_port { -namespace internal { - -class Response : public tizen_base::Parcelable { - public: - explicit Response(int result); - Response(); - ~Response() = default; - - int GetResult(); - - void WriteToParcel(tizen_base::Parcel* parcel) const override; - void ReadFromParcel(tizen_base::Parcel* parcel) override; - - private: - int result_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // RESPONSE_INTERNAL_HH_ diff --git a/src/rpc-port-internal.cc b/src/rpc-port-internal.cc deleted file mode 100644 index ba78616..0000000 --- a/src/rpc-port-internal.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2021 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 -#include -#include -#include - -#include - -#include "include/rpc-port-internal.h" -#include "include/rpc-port.h" -#include "peer-cred-internal.hh" -#include "port-internal.hh" - -#undef RPC_API -#define RPC_API extern "C" __attribute__((visibility("default"))) - -namespace { -using namespace rpc_port::internal; - -constexpr uid_t kRegularUidMin = 5000; -std::atomic __target_uid { getuid() }; - -} // namespace - -RPC_API void rpc_port_set_target_uid(uid_t target_uid) { - __target_uid.exchange(target_uid); - set_last_result(RPC_PORT_ERROR_NONE); -} - -RPC_API uid_t rpc_port_get_target_uid(void) { - if (__target_uid < kRegularUidMin) - __target_uid.exchange(tzplatform_getuid(TZ_SYS_DEFAULT_USER)); - - return __target_uid; -} - -RPC_API int rpc_port_register_proc_info(const char* proc_name, bundle* extra) { - if (proc_name == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - int ret = aul_proc_register(proc_name, extra); - if (ret != AUL_R_OK) - return RPC_PORT_ERROR_IO_ERROR; - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_deregister_proc_info(void) { - int ret = aul_proc_deregister(); - if (ret != AUL_R_OK) - return RPC_PORT_ERROR_IO_ERROR; - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_get_peer_info(rpc_port_h h, pid_t* pid, uid_t* uid) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - std::shared_ptr cred(PeerCred::Get(port->GetFd())); - if (cred.get() == nullptr) - return RPC_PORT_ERROR_IO_ERROR; - - if (pid) - *pid = cred->GetPid(); - - if (uid) - *uid = cred->GetUid(); - - return RPC_PORT_ERROR_NONE; -} - diff --git a/src/rpc-port-parcel.cc b/src/rpc-port-parcel.cc deleted file mode 100644 index e78b6da..0000000 --- a/src/rpc-port-parcel.cc +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright (c) 2018 - 2021 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 "include/rpc-port-parcel.h" - -#include -#include -#include - -#include - -#include "log-private.hh" -#include "parcel-internal.hh" -#include "port-internal.hh" - -#define MAX_PARCEL_SIZE (1024 * 1024 * 10) - -#undef RPC_API -#define RPC_API extern "C" __attribute__((visibility("default"))) - -using namespace rpc_port; - -RPC_API int rpc_port_parcel_create(rpc_port_parcel_h* h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = new (std::nothrow) internal::Parcel(); - if (parcel == nullptr) - return RPC_PORT_ERROR_OUT_OF_MEMORY; - - *h = static_cast(parcel); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_create_from_port(rpc_port_parcel_h* h, - rpc_port_h port) { - int len; - unsigned char* buf; - - if (h == nullptr || port == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - internal::Port* pt = static_cast(port); - { - std::lock_guard lock(pt->GetMutex()); - int ret = rpc_port_read(port, &len, 4); - if (ret != 0) - return ret; - - if (len <= 0 || len > MAX_PARCEL_SIZE) - return RPC_PORT_ERROR_IO_ERROR; - - buf = static_cast(malloc(len)); - if (buf == nullptr) { - _E("Out of memory"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - ret = rpc_port_read(port, buf, len); - if (ret != 0) { - free(buf); // LCOV_EXCL_LINE - return ret; // LCOV_EXCL_LINE - } - } - - auto* parcel = new (std::nothrow) internal::Parcel(); - if (parcel == nullptr) { - // LCOV_EXCL_START - _E("Out of memory"); - free(buf); - return RPC_PORT_ERROR_IO_ERROR; - // LCOV_EXCL_STOP - } - - tizen_base::Parcel raw_parcel(buf, len, false); - raw_parcel.ReadParcelable(parcel); - *h = static_cast(parcel); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_send(rpc_port_parcel_h h, rpc_port_h port) { - if (h == nullptr || port == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - tizen_base::Parcel raw_parcel; - raw_parcel.WriteParcelable(*parcel); - void* raw = reinterpret_cast(raw_parcel.GetData()); - uint32_t len = static_cast(raw_parcel.GetDataSize()); - if (len <= 0) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - internal::Port* pt = static_cast(port); - { - std::lock_guard lock(pt->GetMutex()); - int ret = rpc_port_write(port, &len, sizeof(len)); - if (ret != 0) - return ret; - - ret = rpc_port_write(port, raw, len); - if (ret != 0) - return ret; - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_destroy(rpc_port_parcel_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - delete parcel; - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_byte(rpc_port_parcel_h h, char b) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_byte(parcel->GetHandle(), b); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_int16(rpc_port_parcel_h h, short i) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_int16(parcel->GetHandle(), i); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_int32(rpc_port_parcel_h h, int i) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_int32(parcel->GetHandle(), i); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_int64(rpc_port_parcel_h h, long long i) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_int64(parcel->GetHandle(), i); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_float(rpc_port_parcel_h h, float f) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_float(parcel->GetHandle(), f); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_double(rpc_port_parcel_h h, double d) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_double(parcel->GetHandle(), d); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_string(rpc_port_parcel_h h, const char* str) { - if (h == nullptr || str == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_string(parcel->GetHandle(), str); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_bool(rpc_port_parcel_h h, bool b) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_bool(parcel->GetHandle(), b); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_bundle(rpc_port_parcel_h h, bundle* b) { - if (h == nullptr || b == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - bundle_raw* raw = nullptr; - int len = 0; - bundle_encode(b, &raw, &len); - auto ptr = std::unique_ptr(raw, std::free); - - auto* parcel = static_cast(h); - parcel_write_string(parcel->GetHandle(), reinterpret_cast(raw)); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write_array_count(rpc_port_parcel_h h, int count) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_write_int32(parcel->GetHandle(), count); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_write(rpc_port_parcel_h h, - rpc_port_parcelable_t* parcelable, void* data) { - if (parcelable == nullptr || parcelable->to == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - parcelable->to(h, data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_byte(rpc_port_parcel_h h, char* b) { - if (h == nullptr || b == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_byte(parcel->GetHandle(), b); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_byte() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_int16(rpc_port_parcel_h h, short* i) { - if (h == nullptr || i == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_int16(parcel->GetHandle(), i); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_int16() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_int32(rpc_port_parcel_h h, int* i) { - if (h == nullptr || i == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_int32(parcel->GetHandle(), i); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_int32() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_int64(rpc_port_parcel_h h, long long* i) { - if (h == nullptr || i == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int64_t val = 0; - int ret = parcel_read_int64(parcel->GetHandle(), &val); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_int64() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - *i = static_cast(val); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_float(rpc_port_parcel_h h, float* f) { - if (h == nullptr || f == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_float(parcel->GetHandle(), f); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_float() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_double(rpc_port_parcel_h h, double* d) { - if (h == nullptr || d == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_double(parcel->GetHandle(), d); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read_double() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_string(rpc_port_parcel_h h, char** str) { - if (h == nullptr || str == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_string(parcel->GetHandle(), str); - if (ret != PARCEL_ERROR_NONE) { - _E("parcel_read_string() is failed. error(%d)", ret); // LCOV_EXCL_LINE - *str = strdup(""); // LCOV_EXCL_LINE - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_bool(rpc_port_parcel_h h, bool* b) { - if (h == nullptr || b == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_bool(parcel->GetHandle(), b); - if (ret != 0) - _E("parcel_read_bool() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_bundle(rpc_port_parcel_h h, bundle** b) { - if (h == nullptr || b == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - char* raw = nullptr; - int ret = parcel_read_string(parcel->GetHandle(), &raw); - if (ret != 0) { - _E("parcel_read_string() is failed. error(%d)", ret); // LCOV_EXCL_LINE - *b = bundle_create(); // LCOV_EXCL_LINE - } else { - *b = bundle_decode(reinterpret_cast(raw), strlen(raw)); - std::free(raw); - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read_array_count(rpc_port_parcel_h h, int* count) { - if (h == nullptr || count == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - int ret = parcel_read_int32(parcel->GetHandle(), count); - if (ret != 0) - _E("parcel_read_int32() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_read(rpc_port_parcel_h h, - rpc_port_parcelable_t* parcelable, void* data) { - if (parcelable == nullptr || parcelable->from == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - parcelable->from(h, data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_burst_read(rpc_port_parcel_h h, unsigned char *buf, - unsigned int size) { - if (h == nullptr || buf == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - uint32_t valid_size = size & UINT32_MAX; - int ret = parcel_burst_read(parcel->GetHandle(), static_cast(buf), - valid_size); - if (ret != PARCEL_ERROR_NONE) - _E("parcel_read() is failed. error(%d)", ret); // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_burst_write(rpc_port_parcel_h h, - const unsigned char *buf, unsigned int size) { - if (h == nullptr || buf == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - uint32_t valid_size = size & UINT32_MAX; - parcel_burst_write(parcel->GetHandle(), static_cast(buf), - valid_size); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_reset_reader(rpc_port_parcel_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - parcel_reset_reader(parcel->GetHandle()); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_to_array(rpc_port_parcel_h h, void** array, - unsigned int* size) { - if (h == nullptr || !array || !size) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - tizen_base::Parcel raw_parcel; - raw_parcel.WriteParcelable(*parcel); - void* raw = raw_parcel.GetData(); - size_t raw_size = raw_parcel.GetDataSize(); - if (raw_size == 0) { - _E("raw_size is zero"); - return RPC_PORT_ERROR_IO_ERROR; - } - - void* array_ptr = malloc(raw_size); - if (array_ptr == nullptr) - return RPC_PORT_ERROR_OUT_OF_MEMORY; - - memcpy(array_ptr, raw, raw_size); - *array = array_ptr; - *size = static_cast(raw_size); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_from_array(rpc_port_parcel_h h, const void* array, - unsigned int size) { - if (h == nullptr || array == nullptr || size == 0) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - uint32_t valid_size = size & UINT32_MAX; - tizen_base::Parcel raw_parcel(array, valid_size); - raw_parcel.ReadParcelable(parcel); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_get_header(rpc_port_parcel_h h, - rpc_port_parcel_header_h* header) { - if (h == nullptr || header == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - auto* parcel_header = parcel->GetParcelHeader(); - if (parcel_header == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - *header = reinterpret_cast( - const_cast(parcel_header)); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_header_set_tag(rpc_port_parcel_header_h header, - const char* tag) { - if (header == nullptr || tag == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel_header = static_cast(header); - parcel_header->SetTag(tag); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_header_get_tag(rpc_port_parcel_header_h header, - char** tag) { - if (header == nullptr || tag == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel_header = static_cast(header); - const std::string& raw_tag = parcel_header->GetTag(); - - *tag = strdup(raw_tag.c_str()); - if (*tag == nullptr) - return RPC_PORT_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_header_set_seq_num(rpc_port_parcel_header_h header, - int seq_num) { - if (header == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel_header = static_cast(header); - parcel_header->SetSeqNum(seq_num); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_header_get_seq_num(rpc_port_parcel_header_h header, - int* seq_num) { - if (header == nullptr || seq_num == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel_header = static_cast(header); - *seq_num = parcel_header->GetSeqNum(); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_header_get_timestamp( - rpc_port_parcel_header_h header, struct timespec* timestamp) { - if (header == nullptr || timestamp == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel_header = static_cast(header); - *timestamp = parcel_header->GetTimeStamp(); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_get_raw(rpc_port_parcel_h h, void** raw, - unsigned int* size) { - if (h == nullptr || raw == nullptr || size == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = static_cast(h); - auto* raw_parcel = new (std::nothrow) tizen_base::Parcel(); - if (raw_parcel != nullptr) { - raw_parcel->WriteParcelable(*parcel); - parcel->SetRawParcel(raw_parcel); - *raw = raw_parcel->GetData(); - *size = static_cast(raw_parcel->GetDataSize()); - } else { - // LCOV_EXCL_START - _E("Out of memory"); - *raw = nullptr; - *size = 0; - // LCOV_EXCL_STOP - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_create_from_raw(rpc_port_parcel_h* h, - const void* raw, unsigned int size) { - if (h == nullptr || raw == nullptr || size == 0) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - rpc_port_parcel_h parcel; - int ret = rpc_port_parcel_create(&parcel); - if (ret != RPC_PORT_ERROR_NONE) - return ret; - - ret = rpc_port_parcel_from_array(parcel, raw, size); - if (ret != RPC_PORT_ERROR_NONE) { - rpc_port_parcel_destroy(parcel); // LCOV_EXCL_LINE - return ret; // LCOV_EXCL_LINE - } - - *h = parcel; - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_parcel_create_without_header(rpc_port_parcel_h* h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto* parcel = new (std::nothrow) internal::Parcel(true); - if (parcel == nullptr) - return RPC_PORT_ERROR_OUT_OF_MEMORY; - - *h = static_cast(parcel); - return RPC_PORT_ERROR_NONE; -} diff --git a/src/rpc-port.cc b/src/rpc-port.cc deleted file mode 100644 index 023a9ab..0000000 --- a/src/rpc-port.cc +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 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 "include/rpc-port.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "include/rpc-port-internal.h" -#include "log-private.hh" -#include "port-internal.hh" -#include "proxy-internal.hh" -#include "stub-internal.hh" - -#undef RPC_API -#define RPC_API extern "C" __attribute__((visibility("default"))) - -namespace { -using namespace rpc_port::internal; - -template -class Event { - public: - Event(T cb, void* user_data) - : cb_(cb), user_data_(user_data) {} - - T cb_; - void* user_data_; -}; - -class ProxyExt : public Proxy, public Proxy::IEventListener { - public: - ProxyExt() : Proxy(), destroying_(false) {} - virtual ~ProxyExt() = default; - - void AddConnectedEventListener(rpc_port_proxy_connected_event_cb cb, - void* user_data) { - connected_events_.emplace_back( - new Event(cb, user_data)); - } - - void AddDisconnectedEventListener(rpc_port_proxy_disconnected_event_cb cb, - void* user_data) { - disconnected_events_.emplace_back( - new Event(cb, user_data)); - } - - void AddRejectedEventListener(rpc_port_proxy_rejected_event_cb cb, - void* user_data) { - rejected_events_.emplace_back( - new Event(cb, user_data)); - } - - void AddReceivedEventListener(rpc_port_proxy_received_event_cb cb, - void* user_data) { - received_events_.emplace_back( - new Event(cb, user_data)); - } - - void OnConnected(const std::string& endpoint, Port* port) override { - if (IsDestroying()) - return; - - for (auto& ev : connected_events_) { - ev->cb_(endpoint.c_str(), GetPortName().c_str(), port, - ev->user_data_); - } - } - - void OnDisconnected(const std::string& endpoint) override { - if (IsDestroying()) - return; - - for (auto& ev : disconnected_events_) { - ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); - } - } - - void OnRejected(const std::string& endpoint, int err_code) override { - if (IsDestroying()) - return; - - for (auto& ev : rejected_events_) { - set_last_result(err_code); - ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); - } - } - - void OnReceived(const std::string& endpoint) override { - if (IsDestroying()) - return; - - for (auto& ev : received_events_) { - ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); - } - } - - std::recursive_mutex& GetMutex() const { - return mutex_; - } - - void SetDestroying(bool destroying) { - destroying_ = destroying; - } - - bool IsDestroying() { - return destroying_; - } - - private: - std::atomic destroying_; - std::list>> - connected_events_; - std::list>> - disconnected_events_; - std::list>> - rejected_events_; - std::list>> - received_events_; - mutable std::recursive_mutex mutex_; -}; - -class StubExt : public Stub, public Stub::IEventListener { - public: - explicit StubExt(const std::string& port) : Stub(port), destroying_(false) {} - virtual ~StubExt() = default; - - void AddConnectedEventListener(rpc_port_stub_connected_event_cb cb, - void* user_data) { - connected_events_.emplace_back( - new Event(cb, user_data)); - } - - void AddDisconnectedEventListener(rpc_port_stub_disconnected_event_cb cb, - void* user_data) { - disconnected_events_.emplace_back( - new Event(cb, user_data)); - } - - void AddReceivedEventListener(rpc_port_stub_received_event_cb cb, - void* user_data) { - received_events_.emplace_back( - new Event(cb, user_data)); - } - - void OnConnected(const std::string& sender, - const std::string& instance) override { - if (IsDestroying()) - return; - - for (auto& ev : connected_events_) { - ev->cb_(sender.c_str(), instance.c_str(), ev->user_data_); - } - } - - void OnDisconnected(const std::string& sender, - const std::string& instance) override { - if (IsDestroying()) - return; - - for (auto& ev : disconnected_events_) { - ev->cb_(sender.c_str(), instance.c_str(), ev->user_data_); - } - } - - int OnReceived(const std::string& sender, - const std::string& instance, Port* port) override { - if (IsDestroying()) - return -1; - - for (auto& ev : received_events_) { - int ret = ev->cb_(sender.c_str(), instance.c_str(), port, - ev->user_data_); - if (ret != 0) - return -1; - } - - return 0; - } - - void SetDestroying(bool destroying) { - destroying_ = destroying; - } - - bool IsDestroying() { - return destroying_; - } - - std::recursive_mutex& GetMutex() const { - return mutex_; - } - - private: - std::atomic destroying_; - std::list>> - connected_events_; - std::list>> - disconnected_events_; - std::list>> - received_events_; - mutable std::recursive_mutex mutex_; -}; - -} // namespace - -RPC_API int rpc_port_read(rpc_port_h h, void* buf, unsigned int size) { - if (h == nullptr || buf == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - uint32_t seq = 0; - if (DebugPort::IsConnected()) { - int ret = port->Read(reinterpret_cast(&seq), sizeof(seq)); - if (ret < 0) { - _E("IO Error"); - return ret; - } - } - - int ret = port->Read(buf, size); - if (ret < 0) { - _E("IO Error"); - return ret; - } - - if (DebugPort::IsConnected()) - DebugPort::Send(port->GetFd(), true, seq, buf, size); - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_write(rpc_port_h h, const void* buf, unsigned int size) { - if (h == nullptr || buf == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - uint32_t seq = port->GetSeq(); - if (DebugPort::IsConnected()) { - int ret = port->Write(reinterpret_cast(&seq), sizeof(seq)); - if (ret < 0) - return ret; - } - - int ret = port->Write(buf, size); - if (ret < 0) - return ret; - - if (DebugPort::IsConnected()) - DebugPort::Send(port->GetFd(), false, seq, buf, size); - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = new (std::nothrow) std::shared_ptr<::ProxyExt>( - new (std::nothrow) ::ProxyExt()); - if (p == nullptr) { - _E("Out of memory"); // LCOV_EXCL_LINE - } else if (p->get() == nullptr) { - // LCOV_EXCL_START - _E("Out of memory"); - delete p; - p = nullptr; - // LCOV_EXCL_STOP - } else { - _W("rpc_port_proxy_create(%p)", p->get()); - } - - *h = p; - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - if (proxy->IsDestroying()) { - _E("already destroyed. handle(%p)", proxy); // LCOV_EXCL_LINE - abort(); // LCOV_EXCL_LINE - } - - _W("rpc_port_proxy_destroy(%p)", proxy); - proxy->SetDestroying(true); - proxy->DisconnectPort(); - - g_idle_add_full(G_PRIORITY_HIGH, - [](gpointer data) -> gboolean { - auto p = static_cast*>(data); - _W("rpc_port_proxy_destroy(%p)", p->get()); - delete p; - return G_SOURCE_REMOVE; - }, h, nullptr); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, - const char* port) { - if (h == nullptr || appid == nullptr || port == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); - std::lock_guard lock(proxy->GetMutex()); - return proxy->Connect(appid, port, proxy); -} - -// LCOV_EXCL_START -RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, - const char* port) { - if (h == nullptr || appid == nullptr || port == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); - std::lock_guard lock(proxy->GetMutex()); - return proxy->ConnectSync(appid, port, proxy); -} -// LCOV_EXCL_STOP - -RPC_API int rpc_port_proxy_add_connected_event_cb(rpc_port_proxy_h h, - rpc_port_proxy_connected_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - std::lock_guard lock(proxy->GetMutex()); - proxy->AddConnectedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_add_disconnected_event_cb(rpc_port_proxy_h h, - rpc_port_proxy_disconnected_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - std::lock_guard lock(proxy->GetMutex()); - proxy->AddDisconnectedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_add_rejected_event_cb(rpc_port_proxy_h h, - rpc_port_proxy_rejected_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - std::lock_guard lock(proxy->GetMutex()); - proxy->AddRejectedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_add_received_event_cb(rpc_port_proxy_h h, - rpc_port_proxy_received_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - std::lock_guard lock(proxy->GetMutex()); - proxy->AddReceivedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_proxy_get_port(rpc_port_proxy_h h, - rpc_port_port_type_e type, rpc_port_h* port) { - if (h == nullptr || port == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast*>(h); - auto* proxy = p->get(); - std::lock_guard lock(proxy->GetMutex()); - rpc_port_h ret_port; - - switch (type) { - case RPC_PORT_PORT_MAIN: - ret_port = static_cast(proxy->GetPort().get()); - if (ret_port == nullptr) - return RPC_PORT_ERROR_IO_ERROR; - *port = ret_port; - break; - case RPC_PORT_PORT_CALLBACK: - ret_port = static_cast(proxy->GetDelegatePort().get()); - if (ret_port == nullptr) - return RPC_PORT_ERROR_IO_ERROR; - *port = ret_port; - break; - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { - if (h == nullptr || port_name == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = new ::StubExt(port_name); - *h = p; - _W("rpc_port_stub_create(%p, %s)", p, port_name); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_destroy(rpc_port_stub_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - _W("rpc_port_stub_destroy(%p)", h); - auto p = static_cast<::StubExt*>(h); - if (p->IsDestroying()) { - _E("already destroyed. handle(%p)", h); // LCOV_EXCL_LINE - abort(); // LCOV_EXCL_LINE - } - - p->SetDestroying(true); - aul_rpc_port_usr_destroy(p->GetPortName().c_str(), rpc_port_get_target_uid()); - p->Ignore(); - g_idle_add_full(G_PRIORITY_HIGH, - [](gpointer data) -> gboolean { - auto p = static_cast<::StubExt*>(data); - _W("rpc_port_stub_destroy(%p)", p); - delete p; - return G_SOURCE_REMOVE; - }, h, nullptr); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_listen(rpc_port_stub_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - _W("rpc_port_stub_listen(%p)", h); - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - int fd = p->CreatePort(); - if (fd < 0) - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - - return p->Listen(p, fd); -} - -RPC_API int rpc_port_stub_add_privilege(rpc_port_stub_h h, - const char* privilege) { - if (h == nullptr || privilege == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddPrivilege(privilege); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_set_trusted(rpc_port_stub_h h, - const bool trusted) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->SetTrusted(trusted); - return RPC_PORT_ERROR_NONE; -} - - -RPC_API int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h, - rpc_port_stub_connected_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddConnectedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_add_disconnected_event_cb(rpc_port_stub_h h, - rpc_port_stub_disconnected_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddDisconnectedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_add_received_event_cb(rpc_port_stub_h h, - rpc_port_stub_received_event_cb cb, void* user_data) { - if (h == nullptr || cb == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddReceivedEventListener(cb, user_data); - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_stub_get_port(rpc_port_stub_h h, - rpc_port_port_type_e type, const char* instance, rpc_port_h* port) { - if (h == nullptr || port == nullptr || instance == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto p = static_cast<::StubExt*>(h); - std::lock_guard lock(p->GetMutex()); - rpc_port_h ret_port; - - switch (type) { - case RPC_PORT_PORT_MAIN: - ret_port = static_cast(p->FindPort(instance).get()); - if (ret_port == nullptr) - return RPC_PORT_ERROR_IO_ERROR; - *port = ret_port; - break; - case RPC_PORT_PORT_CALLBACK: - ret_port = static_cast(p->FindDelegatePort(instance).get()); - if (ret_port == nullptr) - return RPC_PORT_ERROR_IO_ERROR; - *port = ret_port; - break; - } - - return RPC_PORT_ERROR_NONE; -} - -RPC_API int rpc_port_set_private_sharing_array(rpc_port_h h, - const char* paths[], unsigned int size) { - if (h == nullptr || paths == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - - return port->SetPrivateSharing(paths, size); -} - -RPC_API int rpc_port_set_private_sharing(rpc_port_h h, const char* path) { - if (h == nullptr || path == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - - return port->SetPrivateSharing(path); -} - -RPC_API int rpc_port_unset_private_sharing(rpc_port_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - - return port->UnsetPrivateSharing(); -} - -RPC_API int rpc_port_disconnect(rpc_port_h h) { - if (h == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - auto port = static_cast(h); - port->Disconnect(); - - return RPC_PORT_ERROR_NONE; -} diff --git a/src/rpc-port/CMakeLists.txt b/src/rpc-port/CMakeLists.txt new file mode 100644 index 0000000..fdee107 --- /dev/null +++ b/src/rpc-port/CMakeLists.txt @@ -0,0 +1,37 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} RPC_PORT_SRCS) + +ADD_LIBRARY(${TARGET_RPC_PORT} SHARED ${RPC_PORT_SRCS}) +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES SOVERSION ${MAJORVER}) +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES VERSION ${FULLVER}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../include) + +APPLY_PKG_CONFIG(${TARGET_RPC_PORT} PUBLIC + AUL_DEPS + BUNDLE_DEPS + CYNARA_CLIENT_DEPS + CYNARA_CREDS_SOCKET_DEPS + DLOG_DEPS + GIO_DEPS + GIO_UNIX_DEPS + GLIB_DEPS + LIBSYSTEMD_DEPS + LIBTZPLATFORM_CONFIG_DEPS + PARCEL_DEPS + PKGMGR_INFO_DEPS + TIZEN_SHARED_QUEUE_DEPS + UUID_DEPS +) + +TARGET_LINK_LIBRARIES(${TARGET_RPC_PORT} PUBLIC "-Wl,-z,nodelete") + +INSTALL(TARGETS ${TARGET_RPC_PORT} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ + DESTINATION include/rpc-port + FILES_MATCHING + PATTERN "*.h" +) diff --git a/src/rpc-port/ac-internal.cc b/src/rpc-port/ac-internal.cc new file mode 100644 index 0000000..4a746bb --- /dev/null +++ b/src/rpc-port/ac-internal.cc @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2017 - 2021 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 "ac-internal.hh" + +#include +#include +#include +#include +#include +#include + +#include + +#include "aul-internal.hh" +#include "cynara_thread.hh" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { +namespace { + +constexpr const uid_t kRegularUidMin = 5000; + +class Cynara { + public: + class Creds { + public: + Creds(int fd, std::string user, std::string client) + : fd_(fd), user_(std::move(user)), client_(std::move(client)) { + _W("client(%s), user(%s), fd(%d)", client_.c_str(), user_.c_str(), fd); + } + + int GetFd() const { return fd_; } + + const std::string& GetUser() const { return user_; } + + const std::string& GetClient() const { return client_; } + + private: + int fd_; + std::string user_; + std::string client_; + }; + + Cynara() : handle_(nullptr, cynara_finish) { + cynara* handle = nullptr; + if (cynara_initialize(&handle, nullptr) != CYNARA_API_SUCCESS) { + _E("cynara_initialize() is failed"); // LCOV_EXCL_LINE + } else { + handle_.reset(handle); + } + } + + ~Cynara() = default; + + std::shared_ptr FetchCredsFromSocket(int fd) { + char* user = nullptr; + int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user); + if (ret != CYNARA_API_SUCCESS) { + // LCOV_EXCL_START + char buf[128] = { 0, }; + cynara_strerror(ret, buf, sizeof(buf)); + _E("cynara_creds_socket_get_user() is failed. fd(%d), error(%d:%s)", + fd, ret, buf); + return nullptr; + // LCOV_EXCL_STOP + } + auto user_auto = std::unique_ptr(user, free); + + char* client = nullptr; + ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client); + if (ret != CYNARA_API_SUCCESS) { + // LCOV_EXCL_START + char buf[128] = { 0, }; + cynara_strerror(ret, buf, sizeof(buf)); + _E("cynara_creds_socket_get_client() is failed. fd(%d), error(%d:%s)", + fd, ret, buf); + return nullptr; + // LCOV_EXCL_STOP + } + auto client_auto = std::unique_ptr(client, free); + + return std::make_shared(fd, user, client); + } + + int Check(const std::shared_ptr& creds, + const std::string& privilege) const { + std::lock_guard lock(mutex_); + _W("cynara_check() ++ privilege(%s), user(%s)", + privilege.c_str(), creds->GetUser().c_str()); + int ret = cynara_check(handle_.get(), creds->GetClient().c_str(), "", + creds->GetUser().c_str(), privilege.c_str()); + _W("cynara_check() -- privilege(%s), user(%s)", + privilege.c_str(), creds->GetUser().c_str()); + if (ret != CYNARA_API_ACCESS_ALLOWED) { + _E("cynara_check() is not allowed. privilege(%s), error(%d)", + privilege.c_str(), ret); + return -1; + } + + return 0; + } + + private: + std::unique_ptr handle_; + mutable std::recursive_mutex mutex_; +}; + +Cynara cynara_inst; + +} // namespace + +void AccessController::AddPrivilege(std::string privilege) { + privileges_.push_back(std::move(privilege)); +} + +void AccessController::SetTrusted(const bool trusted) { + trusted_ = trusted; +} + +int AccessController::CheckPrivilege(int fd) { + auto creds = cynara_inst.FetchCredsFromSocket(fd); + if (creds == nullptr) return -1; + + for (const auto& privilege : privileges_) { + if (cynara_inst.Check(creds, privilege) != 0) + return -1; + } + + return 0; +} + +// LCOV_EXCL_START +int AccessController::CheckTrusted(const std::string& sender_appid) { + if (getuid() < kRegularUidMin) + return 0; + + if (appid_.empty()) + appid_ = Aul::GetAppId(getpid()); + + _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid.c_str()); + pkgmgrinfo_cert_compare_result_type_e res; + int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(appid_.c_str(), + sender_appid.c_str(), getuid(), &res); + if (ret < 0) { + _E("CheckCertificate() Failed"); + return -1; + } + if (res != PMINFO_CERT_COMPARE_MATCH) { + _E("CheckCertificate() Failed : Certificate Not Matched"); + return -1; + } + + return 0; +} +// LCOV_EXCL_STOP + +int AccessController::Check(int fd, const std::string& sender_appid) { + int ret = 0; + if (!privileges_.empty()) { + ret = CheckPrivilege(fd); + if (ret != 0) + return ret; + } + + if (trusted_) + ret = CheckTrusted(sender_appid); + + return ret; +} + +void AccessController::CheckAsync(int fd, std::string sender_appid, + CompleteCallback callback) { + /* This is for handle freed issue */ + auto* tmp_handle = new std::shared_ptr(shared_from_this()); + Job job([=]() -> Job::Type { + if ((*tmp_handle).use_count() == 1) { + delete tmp_handle; // LCOV_EXCL_LINE + return Job::Type::Continue; // LCOV_EXCL_LINE + } + + int res = Check(fd, sender_appid); + auto* cbdata = new std::pair( + std::move(callback), res); + guint sid = g_idle_add( + [](gpointer data) -> gboolean { + auto* cb_data = static_cast*>(data); + auto [callback, res] = *cb_data; + callback(res); + delete cb_data; + return G_SOURCE_REMOVE; + }, cbdata); + if (sid == 0) { + _E("Failed to call g_idle_add"); // LCOV_EXCL_LINE + delete cbdata; // LCOV_EXCL_LINE + } + + delete tmp_handle; + return Job::Type::Continue; + }); + + CynaraThread::GetInst().Push(std::move(job)); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/ac-internal.hh b/src/rpc-port/ac-internal.hh new file mode 100644 index 0000000..0b48d5c --- /dev/null +++ b/src/rpc-port/ac-internal.hh @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef AC_INTERNAL_HH_ +#define AC_INTERNAL_HH_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace rpc_port { +namespace internal { + +using CompleteCallback = std::function; + +class AccessController : public std::enable_shared_from_this { + public: + explicit AccessController(bool trusted = false) : trusted_(trusted) {} + + void AddPrivilege(std::string privilege); + void SetTrusted(const bool trusted); + int Check(int fd, const std::string& sender_appid); + void CheckAsync(int fd, std::string sender_appid, CompleteCallback callback); + + private: + int CheckTrusted(const std::string& sender_appid); + int CheckPrivilege(int fd); + + private: + std::vector privileges_; + std::map cache_; + bool trusted_; + std::string appid_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // AC_INTERNAL_HH_ diff --git a/src/rpc-port/aul-internal.cc b/src/rpc-port/aul-internal.cc new file mode 100644 index 0000000..628cd5f --- /dev/null +++ b/src/rpc-port/aul-internal.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include + +#include + +#include "aul-internal.hh" +#include "include/rpc-port.h" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +std::string Aul::GetName(int pid) { + char* name = nullptr; + if (aul_proc_get_name(pid, &name) != AUL_R_OK) return ""; + + std::unique_ptr name_auto(name, std::free); + return std::string(name); +} + +std::string Aul::GetAppId(int pid) { + char app_id[256] = { 0, }; + int ret = aul_app_get_appid_bypid(pid, app_id, sizeof(app_id)); + if (ret != AUL_R_OK) { + // LCOV_EXCL_START + _E("aul_app_get_appid_bypid() is failed. pid(%d), error(%d)", pid, ret); + return GetName(pid); + // LCOV_EXCL_STOP + } + + return std::string(app_id); +} + +std::string Aul::GetPortPath(const std::string& app_id, + const std::string& port_name, uid_t uid) { + char* port_path = nullptr; + int ret = aul_rpc_port_usr_get_path(app_id.c_str(), port_name.c_str(), uid, + &port_path); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_get_path() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return {}; // LCOV_EXCL_LINE + } + + std::unique_ptr ptr(port_path, std::free); + return std::string(port_path); +} + +int Aul::PrepareStub(const std::string& app_id, const std::string& port_name, + uid_t uid) { + int ret = aul_rpc_port_usr_prepare_stub(app_id.c_str(), port_name.c_str(), + uid); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_prepare_stub() is failed. error(%d)", ret); + if (ret == AUL_R_EILLACC) + return RPC_PORT_ERROR_PERMISSION_DENIED; + + return RPC_PORT_ERROR_IO_ERROR; + } + + return RPC_PORT_ERROR_NONE; +} + +bool Aul::ExistPort(const std::string& app_id, const std::string& port_name, + uid_t uid) { + bool exist = false; + int ret = aul_rpc_port_usr_exist(app_id.c_str(), port_name.c_str(), uid, + &exist); + if (ret != AUL_R_OK) + _W("aul_rpc_port_usr_exist() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return exist; +} + +void Aul::NotifyRpcFinished() { + int ret = aul_rpc_port_notify_rpc_finished(); + if (ret != AUL_R_OK) + _W("aul_rpc_port_notify_rpc_finished() is failed. error(%d)", ret); // LCOV_EXCL_LINE +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/aul-internal.hh b/src/rpc-port/aul-internal.hh new file mode 100644 index 0000000..3d74be4 --- /dev/null +++ b/src/rpc-port/aul-internal.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef AUL_INTERNAL_HH_ +#define AUL_INTERNAL_HH_ + +#include + +namespace rpc_port { +namespace internal { + +class Aul { + public: + static std::string GetName(int pid); + static std::string GetAppId(int pid); + static std::string GetPortPath(const std::string& app_id, + const std::string& port_name, uid_t uid); + static int PrepareStub(const std::string& app_id, + const std::string& port_name, uid_t uid); + static bool ExistPort(const std::string& app_id, const std::string& port_name, + uid_t uid); + static void NotifyRpcFinished(); +}; + +} // namespace internal +} // namespace rpc_port + +#endif // AUL_INTERNAL_HH_ diff --git a/src/rpc-port/client-socket-internal.cc b/src/rpc-port/client-socket-internal.cc new file mode 100644 index 0000000..9a71b4e --- /dev/null +++ b/src/rpc-port/client-socket-internal.cc @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "client-socket-internal.hh" +#include "exception-internal.hh" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +ClientSocket::ClientSocket() { + fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd_ < 0) { + // LCOV_EXCL_START + fd_ = -errno; + _E("socket() is failed. errno(%d)", errno); + THROW(fd_); + // LCOV_EXCL_STOP + } +} + +ClientSocket::ClientSocket(int fd) : fd_(fd) { + SetCloseOnExec(); +} + +ClientSocket::~ClientSocket() { + if (!IsClosed()) + Close(); +} + +void ClientSocket::SetCloseOnExec() { + int flags = fcntl(fd_, F_GETFL, 0); + fcntl(fd_, F_SETFL, flags | FD_CLOEXEC); + _I("Close on exec. fd(%d)", fd_); +} + +void ClientSocket::Close() { + if (fd_ > -1) { + close(fd_); + fd_ = -1; + } +} + +int ClientSocket::Connect(const std::string& endpoint) { + int flag = fcntl(GetFd(), F_GETFL, 0); + fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); + + struct sockaddr_un sockaddr = { 0, }; + sockaddr.sun_family = AF_UNIX; + snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", + endpoint.c_str()); + struct sockaddr* sockaddr_ptr = reinterpret_cast(&sockaddr); + socklen_t len = static_cast(sizeof(sockaddr)); + int ret = connect(GetFd(), sockaddr_ptr, len); + fcntl(GetFd(), F_SETFL, flag); + if (ret < 0) { + // LCOV_EXCL_START + ret = -errno; + _E("connect() is failed. errno(%d)", errno); + return ret; + // LCOV_EXCL_STOP + } + + return 0; +} + +int ClientSocket::Send(const void* buf, unsigned int size) { + const unsigned char* buffer = static_cast(buf); + size_t len = size; + while (len) { + ssize_t bytes = send(GetFd(), buffer, len, MSG_NOSIGNAL); + if (bytes < 0) { + // LCOV_EXCL_START + int ret = -errno; + _E("send() is failed. fd(%d), errno(%d)", GetFd(), errno); + return ret; + // LCOV_EXCL_STOP + } + + len -= bytes; + buffer += bytes; + } + + return 0; +} + +int ClientSocket::Receive(void* buf, unsigned int size) { + unsigned char* buffer = static_cast(buf); + size_t len = size; + while (len) { + ssize_t bytes = read(GetFd(), buffer, len); + if (bytes == 0) { + _W("EOF. fd(%d)", GetFd()); // LCOV_EXCL_START + return -EIO; // LCOV_EXCL_STOP + } + + if (bytes < 0) { + if (errno == EINTR) { + usleep(100 * 1000); + continue; + } + + return -errno; // LCOV_EXCL_LINE + } + + len -= bytes; + buffer += bytes; + } + + return 0; +} + +void ClientSocket::SetReceiveTimeout(int timeout) { + if (timeout == INT_MAX) + return; // LCOV_EXCL_LINE + + if (timeout == -1) + timeout = 5000; + + if (timeout < 0) { + _E("Invalid parameter"); // LCOV_EXCL_LINE + THROW(-EINVAL); // LCOV_EXCL_LINE + } + + struct timeval tv = { + .tv_sec = static_cast(timeout / 1000), + .tv_usec = static_cast((timeout % 1000) * 1000) + }; + socklen_t len = static_cast(sizeof(struct timeval)); + int ret = setsockopt(GetFd(), SOL_SOCKET, SO_RCVTIMEO, &tv, len); + if (ret < 0) { + // LCOV_EXCL_START + ret = -errno; + _E("setsockopt() is failed. errno(%d)", errno); + THROW(ret); + // LCOV_EXCL_STOP + } +} + +bool ClientSocket::IsClosed() { + return fd_ < 0 ? true : false; +} + +int ClientSocket::GetFd() const { + return fd_; +} + +int ClientSocket::RemoveFd() { + int fd = fd_; + fd_ = -1; + return fd; +} + +void ClientSocket::SetNonblock() { + int flag = fcntl(GetFd(), F_GETFL, 0); + fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/client-socket-internal.hh b/src/rpc-port/client-socket-internal.hh new file mode 100644 index 0000000..d033b2e --- /dev/null +++ b/src/rpc-port/client-socket-internal.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef CLIENT_SOCKET_INTERNAL_HH_ +#define CLIENT_SOCKET_INTERNAL_HH_ + +#include + +namespace rpc_port { +namespace internal { + +class ClientSocket { + public: + ClientSocket(); + explicit ClientSocket(int fd); + virtual ~ClientSocket(); + + void Close(); + int Connect(const std::string& endpoint); + int Send(const void* buf, unsigned int size); + int Receive(void* buf, unsigned int size); + void SetReceiveTimeout(int timeout); + bool IsClosed(); + int GetFd() const; + int RemoveFd(); + void SetNonblock(); + void SetCloseOnExec(); + + private: + int fd_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // CLIENT_SOCKET_INTERNAL_HH_ diff --git a/src/rpc-port/cynara_thread.cc b/src/rpc-port/cynara_thread.cc new file mode 100644 index 0000000..a5a2f67 --- /dev/null +++ b/src/rpc-port/cynara_thread.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 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 "cynara_thread.hh" + +#include + +namespace rpc_port { +namespace internal { + +Job::Job(Job::JobHandlerCallback cb) : cb_(std::move(cb)) {} + +Job::Type Job::Do() { + if (cb_ == nullptr) + return Job::Type::Finish; + + return cb_(); +} + +CynaraThread& CynaraThread::GetInst() { + static CynaraThread* inst = new CynaraThread(); + return *inst; +} + +CynaraThread::CynaraThread() { + thread_ = std::thread([this]() { ThreadRun(); }); +} + +// LCOV_EXCL_START +CynaraThread::~CynaraThread() { + queue_.Push(Job()); + thread_.join(); +} +// LCOV_EXCL_STOP + +void CynaraThread::ThreadRun() { + while (true) { + Job job = queue_.WaitAndPop(); + if (job.Do() == Job::Type::Finish) + return; // LCOV_EXCL_LINE + } +} + +void CynaraThread::Push(Job job) { + queue_.Push(std::move(job)); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/cynara_thread.hh b/src/rpc-port/cynara_thread.hh new file mode 100644 index 0000000..3babdd3 --- /dev/null +++ b/src/rpc-port/cynara_thread.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 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. + */ + +#ifndef CYNARA_THREAD_HH_ +#define CYNARA_THREAD_HH_ + +#include +#include +#include + +namespace rpc_port { +namespace internal { + +class Job { + public: + enum class Type { + Continue = 0, + Finish = 1, + }; + + using JobHandlerCallback = std::function; + + explicit Job(JobHandlerCallback cb = nullptr); + + ~Job() = default; + + Type Do(); + + private: + JobHandlerCallback cb_; +}; + +class CynaraThread { + public: + static CynaraThread& GetInst(); + CynaraThread(CynaraThread&) = delete; + CynaraThread& operator=(CynaraThread&) = delete; + ~CynaraThread(); + + void ThreadRun(); + void Push(Job job); + + private: + CynaraThread(); + Job Pop(); + + std::thread thread_; + mutable tizen_base::SharedQueue queue_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // CYNARA_THREAD_HH_ diff --git a/src/rpc-port/debug-port-internal.cc b/src/rpc-port/debug-port-internal.cc new file mode 100644 index 0000000..eabe432 --- /dev/null +++ b/src/rpc-port/debug-port-internal.cc @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. + * + * 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 "debug-port-internal.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "log-private.hh" +#include "port-internal.hh" + +namespace rpc_port { +namespace internal { +namespace { + +constexpr const char PATH_RPC_PORT_UTIL_SOCK[] = + "/run/aul/daemons/.rpc-port-util-sock"; +constexpr const char ENDPOINT_RPC_PORT_DEBUG[] = "org.tizen.rpcport.debug"; +constexpr const char KEY_PORT_NAME[] = "__K_PORT_NAME__"; + +class Session { + public: + Session(std::string port_name, std::string destination, + int main_port, int delegate_port) + : port_name_(std::move(port_name)), + destination_(std::move(destination)), + main_port_(main_port), + delegate_port_(delegate_port) { + } + + const std::string& GetPortName() const { + return port_name_; + } + + const std::string& GetDestination() const { + return destination_; + } + + int GetMainPort() const { + return main_port_; + } + + int GetDelegatePort() const { + return delegate_port_; + } + + private: + std::string port_name_; + std::string destination_; + int main_port_; + int delegate_port_; +}; + +class DebugPortImpl { + public: + DebugPortImpl() = default; + ~DebugPortImpl(); + + void Dispose(); + bool IsConnected() const; + void AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port); + void RemoveSession(int port); + int Send(int port, bool is_read, uint32_t seq, + const void* buf, unsigned int size); + void Init(); + + private: + int Connect(); + int Watch(int fd); + void Unwatch(); + void SetConnectionStatus(bool status); + void CreateThread(); + void JoinThread(); + + std::recursive_mutex& GetMutex() const; + std::shared_ptr FindSession(int port); + std::shared_ptr FindSession(const std::string& port_name); + + static gboolean OnDebugPortDisconnectedCb(GIOChannel* io, + GIOCondition cond, gpointer data); + static int AppComCb(const char* endpoint, aul_app_com_result_e result, + bundle* envelope, void* user_data); + + private: + bool disposed_ = true; + std::atomic connected_ { false }; + std::unique_ptr port_; + GIOChannel* io_ = nullptr; + guint watch_tag_ = 0; + std::list> sessions_; + std::thread thread_; + std::atomic is_running_ { false }; + tizen_base::SharedQueue> queue_; + mutable std::recursive_mutex mutex_; + aul_app_com_connection_h conn_ = nullptr; +}; + +DebugPortImpl::~DebugPortImpl() { + Dispose(); +} + +void DebugPortImpl::Dispose() { + std::lock_guard lock(GetMutex()); + if (disposed_) + return; + + if (conn_) { + aul_app_com_leave(conn_); + conn_ = nullptr; + } + + Unwatch(); + JoinThread(); + disposed_ = true; +} + +bool DebugPortImpl::IsConnected() const { + return connected_; +} + +void DebugPortImpl::AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port) { + std::lock_guard lock(GetMutex()); + sessions_.emplace_back( + new Session(std::move(port_name), std::move(destination), + main_port, delegate_port)); +} + +void DebugPortImpl::RemoveSession(int port) { + std::lock_guard lock(GetMutex()); + auto iter = std::find_if(sessions_.begin(), sessions_.end(), + [port](std::shared_ptr& sess) -> bool { + return sess->GetMainPort() == port || sess->GetDelegatePort() == port; + }); + + if (iter != sessions_.end()) { + _W("Remove session. port(%d)", port); + iter = sessions_.erase(iter); + } +} + +std::shared_ptr DebugPortImpl::FindSession(int port) { + std::lock_guard lock(GetMutex()); + for (auto& s : sessions_) { + if (s->GetMainPort() == port || s->GetDelegatePort() == port) + return s; + } + + return nullptr; +} + +std::shared_ptr DebugPortImpl::FindSession( + const std::string& port_name) { + std::lock_guard lock(GetMutex()); + for (auto& s : sessions_) { + if (s->GetPortName() == port_name) + return s; + } + + return nullptr; +} + +int DebugPortImpl::Send(int port, bool is_read, uint32_t seq, + const void* buf, unsigned int size) { + if (!IsConnected()) + return 0; + + auto session = FindSession(port); + if (session == nullptr) { + _E("Failed to find session. port(%d)", port); + return -1; + } + + // time + port_name + destination + is_delegate + port + is_read + seq + size + data + tizen_base::Parcel parcel; + parcel.WriteInt64(time(nullptr)); + parcel.WriteString(session->GetPortName().c_str()); + parcel.WriteString(session->GetDestination().c_str()); + parcel.WriteBool(session->GetDelegatePort() == port); + parcel.WriteInt32(port); + parcel.WriteBool(is_read); + parcel.WriteInt32(seq); + parcel.WriteInt32(size); + parcel.Write(static_cast(buf), size); + + queue_.Push(std::make_shared(parcel)); + return 0; +} + +void DebugPortImpl::Init() { + std::lock_guard lock(GetMutex()); + if (!disposed_) + return; + + aul_app_com_create_async(ENDPOINT_RPC_PORT_DEBUG, nullptr, AppComCb, this, + &conn_); + if (conn_ == nullptr) + return; + + do { + int fd = Connect(); + if (fd < 0) + break; + + port_.reset(new Port(fd, "Debug")); + if (Watch(fd) < 0) + break; + + SetConnectionStatus(true); + _W("Connected"); + CreateThread(); + } while (0); + + disposed_ = false; +} + +int DebugPortImpl::Connect() { + if (access(PATH_RPC_PORT_UTIL_SOCK, F_OK) != 0) + return -1; + + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + _E("socket() is failed. errno(%d)", errno); + return -1; + } + + struct sockaddr_un addr = { 0, }; + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_RPC_PORT_UTIL_SOCK); + + int ret = connect(fd, reinterpret_cast(&addr), + sizeof(addr)); + if (ret < 0) { + _E("connect() is failed. fd(%d), errno(%d)", fd, errno); + close(fd); + return -1; + } + + return fd; +} + +int DebugPortImpl::Watch(int fd) { + GIOChannel* io = g_io_channel_unix_new(fd); + if (io == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + GIOCondition cond = static_cast( + (G_IO_ERR | G_IO_HUP | G_IO_NVAL)); + guint tag = g_io_add_watch(io, cond, OnDebugPortDisconnectedCb, this); + if (tag == 0) { + _E("g_io_add_watch() is failed"); + g_io_channel_unref(io); + return -1; + } + + io_ = io; + watch_tag_ = tag; + return 0; +} + +void DebugPortImpl::Unwatch() { + if (io_) { + g_io_channel_unref(io_); + io_ = nullptr; + } + + if (watch_tag_) { + g_source_remove(watch_tag_); + watch_tag_ = 0; + } +} + +gboolean DebugPortImpl::OnDebugPortDisconnectedCb(GIOChannel* io, + GIOCondition cond, gpointer data) { + _W("cond(%d)", static_cast(cond)); + auto* debug_port = static_cast(data); + std::lock_guard lock(debug_port->GetMutex()); + debug_port->SetConnectionStatus(false); + debug_port->watch_tag_ = 0; + debug_port->Unwatch(); + debug_port->port_.reset(); + _W("Disconnected"); + return G_SOURCE_REMOVE; +} + +void DebugPortImpl::SetConnectionStatus(bool status) { + connected_.exchange(status); +} + +void DebugPortImpl::CreateThread() { + if (is_running_) + return; + + thread_ = std::thread([&]() { + _W("START"); + do { + std::shared_ptr parcel = queue_.WaitAndPop(); + int len = parcel->GetDataSize(); + if (len == 0) { + _W("Done"); + break; + } + + if (!IsConnected()) + continue; + + int ret = port_->Write(reinterpret_cast(&len), sizeof(len)); + if (ret < 0) { + _E("Failed to write size"); + SetConnectionStatus(false); + continue; + } + + ret = port_->Write(parcel->GetData(), len); + if (ret < 0) { + _E("Failed to write data"); + SetConnectionStatus(false); + } + } while (true); + _W("END"); + }); + + is_running_ = true; +} + +void DebugPortImpl::JoinThread() { + if (is_running_) + queue_.Push(std::shared_ptr(new tizen_base::Parcel())); + + if (thread_.joinable()) { + _W("Join thread"); + thread_.join(); + } +} + + +std::recursive_mutex& DebugPortImpl::GetMutex() const { + return mutex_; +} + +int DebugPortImpl::AppComCb(const char* endpoint, aul_app_com_result_e result, + bundle* envelope, void* user_data) { + const char* val = bundle_get_val(envelope, KEY_PORT_NAME); + if (val == nullptr) + return -1; + + auto* handle = static_cast(user_data); + std::string port_name(val); + if (port_name.empty() || handle->FindSession(port_name) != nullptr) { + auto* handle = static_cast(user_data); + int fd = handle->Connect(); + if (fd < 0) + return -1; + + std::lock_guard lock(handle->GetMutex()); + handle->port_.reset(new Port(fd, "Debug")); + int ret = handle->Watch(fd); + if (ret < 0) + return -1; + + handle->SetConnectionStatus(true); + _W("Connected"); + handle->CreateThread(); + } + + return 0; +} + +DebugPortImpl impl; + +} // namespace + +bool DebugPort::IsConnected() { + impl.Init(); + return impl.IsConnected(); +} + +void DebugPort::AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port) { + impl.Init(); + return impl.AddSession(std::move(port_name), std::move(destination), + main_port, delegate_port); +} + +void DebugPort::RemoveSession(int port) { + impl.Init(); + return impl.RemoveSession(port); +} + +int DebugPort::Send(int port, bool is_read, uint32_t seq, const void* buf, + unsigned int size) { + impl.Init(); + return impl.Send(port, is_read, seq, buf, size); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/debug-port-internal.hh b/src/rpc-port/debug-port-internal.hh new file mode 100644 index 0000000..9b68c65 --- /dev/null +++ b/src/rpc-port/debug-port-internal.hh @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef DEBUG_PORT_INTERNAL_HH_ +#define DEBUG_PORT_INTERNAL_HH_ + +#include +#include + +namespace rpc_port { +namespace internal { + +class DebugPort { + public: + static bool IsConnected(); + static void AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port); + static void RemoveSession(int port); + static int Send(int port, bool is_read, uint32_t seq, + const void* buf, unsigned int size); +}; + +} // namespace internal +} // namespace rpc_port + +#endif // DEBUG_PORT_INTERNAL_HH_ diff --git a/src/rpc-port/exception-internal.cc b/src/rpc-port/exception-internal.cc new file mode 100644 index 0000000..51a7bb9 --- /dev/null +++ b/src/rpc-port/exception-internal.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 "exception-internal.hh" + +#include + +namespace rpc_port { +namespace internal { + +// LCOV_EXCL_START +Exception::Exception(int error_code, const std::string& file, int line) + : error_code_(error_code), + message_(std::move(GetErrorMessage(error_code_, file, line))) { +} + +const char* Exception::what() const noexcept { + return message_.c_str(); +} + +int Exception::GetErrorCode() { + return error_code_; +} + +std::string Exception::GetErrorMessage(int error_code, const std::string& file, + int line) { + return file.substr(file.find_last_of("/") + 1) + ":" + std::to_string(line) + + " error_code: " + std::to_string(error_code); +} +// LCOV_EXCL_STOP + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/exception-internal.hh b/src/rpc-port/exception-internal.hh new file mode 100644 index 0000000..226c909 --- /dev/null +++ b/src/rpc-port/exception-internal.hh @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef EXCEPTION_INTERNAL_HH_ +#define EXCEPTION_INTERNAL_HH_ + +#include +#include + +#define THROW(error_code) throw Exception(error_code, __FUNCTION__, __LINE__) + +namespace rpc_port { +namespace internal { + +class Exception : public std::exception { + public: + explicit Exception(int error_code, const std::string& file, int line); + virtual ~Exception() = default; // LCOV_EXCL_LINE + + virtual const char* what() const noexcept; + int GetErrorCode(); + + private: + static std::string GetErrorMessage(int error_code, const std::string& file, + int line); + + private: + int error_code_; + std::string message_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // EXCEPTION_INTERNAL_HH_ diff --git a/src/rpc-port/file-monitor-internal.cc b/src/rpc-port/file-monitor-internal.cc new file mode 100644 index 0000000..f8b0303 --- /dev/null +++ b/src/rpc-port/file-monitor-internal.cc @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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 "file-monitor-internal.hh" + +#include +#include +#include + +#include +#include + +#include "exception-internal.hh" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { +namespace fs = std::filesystem; + +FileMonitor::FileMonitor(std::string path, IEvent* listener) + : path_(std::move(path)), listener_(listener) { + const auto fs_path = fs::path(path_); + parent_path_ = fs_path.parent_path().string(); + file_name_ = fs_path.filename().string(); + _W("path=%s, parent_path=%s, file_name=%s", + path_.c_str(), parent_path_.c_str(), file_name_.c_str()); +} + +FileMonitor::~FileMonitor() { + _W("path=%s", path_.c_str()); + Stop(); +} + +bool FileMonitor::Exist() { + if (access(path_.c_str(), F_OK) == 0) return true; + + return false; +} + +void FileMonitor::Start() { + fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (fd_ < 0) { + _E("inotify_init1() is failed. errno(%d)", errno); + THROW(-1); + } + + wd_ = inotify_add_watch(fd_, parent_path_.c_str(), IN_CREATE | IN_DELETE); + if (wd_ < 0) { + _E("inotify_add_watch() is failed. errno(%d)", errno); + Stop(); + THROW(-1); + } + + channel_ = g_io_channel_unix_new(fd_); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); + Stop(); + THROW(-1); + } + + source_ = g_io_create_watch(channel_, G_IO_IN); + if (source_ == nullptr) { + _E("g_io_create_watch() is failed"); + Stop(); + THROW(-1); + } + + g_source_set_callback(source_, reinterpret_cast(GIOFunc), this, + nullptr); + g_source_attach(source_, nullptr); + g_source_unref(source_); +} + +void FileMonitor::Stop() { + if (source_ && !g_source_is_destroyed(source_)) { + g_source_destroy(source_); + source_ = nullptr; + } + + if (channel_) { + g_io_channel_unref(channel_); + channel_ = nullptr; + } + + if (wd_ > -1) { + inotify_rm_watch(fd_, wd_); + wd_ = -1; + } + + if (fd_ > -1) { + close(fd_); + fd_ = -1; + } +} + +gboolean FileMonitor::GIOFunc(GIOChannel* channel, GIOCondition condition, + gpointer user_data) { + char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); + auto* monitor = static_cast(user_data); + auto* listener = monitor->listener_; + int fd = g_io_channel_unix_get_fd(channel); + struct inotify_event* event; + ssize_t len; + char* ptr; + char* nptr; + + while ((len = read(fd, buf, sizeof(buf))) > 0) { + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + event->len) { + event = reinterpret_cast(ptr); + nptr = ptr + sizeof(struct inotify_event) + event->len; + if (nptr > buf + len) break; + + if (monitor->file_name_ != event->name) continue; + + if (event->mask & IN_CREATE) { + listener->OnFileCreated(monitor->path_); + return G_SOURCE_CONTINUE; + } + + if (event->mask & IN_DELETE) + listener->OnFileDeleted(monitor->path_); + } + } + + return G_SOURCE_CONTINUE; +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/file-monitor-internal.hh b/src/rpc-port/file-monitor-internal.hh new file mode 100644 index 0000000..2058402 --- /dev/null +++ b/src/rpc-port/file-monitor-internal.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef FILE_MONITOR_INTERNAL_HH_ +#define FILE_MONITOR_INTERNAL_HH_ + +#include +#include + +#include + +namespace rpc_port { +namespace internal { + +class FileMonitor { + public: + class IEvent { + public: + virtual ~IEvent() = default; + virtual void OnFileCreated(const std::string& path) = 0; + virtual void OnFileDeleted(const std::string& path) = 0; + }; + + explicit FileMonitor(std::string path, IEvent* listener = nullptr); + ~FileMonitor(); + + void Start(); + void Stop(); + bool Exist(); + + private: + static gboolean GIOFunc(GIOChannel* channel, GIOCondition condition, + gpointer user_data); + + private: + std::string path_; + std::string parent_path_; + std::string file_name_; + IEvent* listener_ = nullptr; + int fd_ = -1; + int wd_ = -1; + GIOChannel* channel_ = nullptr; + GSource* source_ = nullptr; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // FILE_MONITOR_INTERNAL_HH_ diff --git a/src/rpc-port/log-private.hh b/src/rpc-port/log-private.hh new file mode 100644 index 0000000..36aeb9c --- /dev/null +++ b/src/rpc-port/log-private.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef LOG_PRIVATE_HH_ +#define LOG_PRIVATE_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "RPC_PORT" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // LOG_PRIVATE_HH_ diff --git a/src/rpc-port/message-sending-thread-internal.cc b/src/rpc-port/message-sending-thread-internal.cc new file mode 100644 index 0000000..b21eddd --- /dev/null +++ b/src/rpc-port/message-sending-thread-internal.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 "log-private.hh" +#include "message-sending-thread-internal.hh" + +namespace rpc_port { +namespace internal { + +// LCOV_EXCL_START +MessageSendingThread& MessageSendingThread::GetInst() { + static MessageSendingThread inst; + return inst; +} + +MessageSendingThread::MessageSendingThread() { + context_ = g_main_context_new(); + loop_ = g_main_loop_new(context_, false); + std::unique_lock lock(mutex_); + thread_ = std::make_unique([&]() -> void { ThreadLoop(); }); + cond_.wait(lock, [&] { return thread_ok_; }); +} + +MessageSendingThread::~MessageSendingThread() { + Dispose(); +} + +gboolean MessageSendingThread::NotifyOne(gpointer data) { + auto* sender = static_cast(data); + std::unique_lock lock(sender->mutex_); + sender->thread_ok_ = true; + sender->cond_.notify_one(); + return G_SOURCE_REMOVE; +} + +void MessageSendingThread::ThreadLoop() { + { + std::unique_lock lock(mutex_); + GSource* source = g_idle_source_new(); + if (source == nullptr) { + _E("Failed to create GSource"); + cond_.notify_one(); + return; + } + + g_source_set_callback(source, NotifyOne, this, nullptr); + g_source_set_priority(source, G_PRIORITY_HIGH); + g_source_attach(source, context_); + g_source_unref(source); + + g_main_context_push_thread_default(context_); + } + + g_main_loop_run(loop_); + + g_main_context_pop_thread_default(context_); + _W("Shutdown message sending thread"); +} + +void MessageSendingThread::Dispose() { + std::unique_lock lock(mutex_); + if (g_main_loop_is_running(loop_)) + g_main_loop_quit(loop_); + else + _E("GMainLoop is not running"); + + thread_->join(); + + g_main_loop_unref(loop_); + loop_ = nullptr; + + g_main_context_unref(context_); + context_ = nullptr; +} + +GMainContext* MessageSendingThread::GetContext() { + return context_; +} +// LCOV_EXCL_STOP + +} // namespace internal +} // namespace rpc_port + diff --git a/src/rpc-port/message-sending-thread-internal.hh b/src/rpc-port/message-sending-thread-internal.hh new file mode 100644 index 0000000..1d3acad --- /dev/null +++ b/src/rpc-port/message-sending-thread-internal.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef MESSAGE_SENDING_THREAD_INTERNAL_HH_ +#define MESSAGE_SENDING_THREAD_INTERNAL_HH_ + +#include +#include + +#include +#include +#include +#include +#include + +#include "port-internal.hh" + +namespace rpc_port { +namespace internal { + +class MessageSendingThread { + public: + static MessageSendingThread& GetInst(); + ~MessageSendingThread(); + GMainContext* GetContext(); + + private: + MessageSendingThread(); + void ThreadLoop(); + void Dispose(); + static gboolean NotifyOne(gpointer data); + + GMainContext* context_ = nullptr; + GMainLoop* loop_ = nullptr; + bool thread_ok_ = false; + std::unique_ptr thread_; + std::mutex mutex_; + std::condition_variable cond_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // MESSAGE_SENDING_THREAD_INTERNAL_HH_ diff --git a/src/rpc-port/parcel-header-internal.cc b/src/rpc-port/parcel-header-internal.cc new file mode 100644 index 0000000..f4413dd --- /dev/null +++ b/src/rpc-port/parcel-header-internal.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include + +#include "parcel-header-internal.hh" + +namespace rpc_port { +namespace internal { + +ParcelHeader::ParcelHeader() : seq_num_(GenerateSeqNum()) { + clock_gettime(CLOCK_MONOTONIC_RAW, &time_stamp_); +} + +void ParcelHeader::WriteToParcel(tizen_base::Parcel* parcel) const { + parcel->WriteString(tag_); + parcel->WriteInt32(seq_num_); + parcel->WriteInt64(static_cast(time_stamp_.tv_sec)); + parcel->WriteInt64(static_cast(time_stamp_.tv_nsec)); +} + +void ParcelHeader::ReadFromParcel(tizen_base::Parcel* parcel) { + tag_ = std::move(parcel->ReadString()); + parcel->ReadInt32(&seq_num_); + + int64_t tv_sec = 0; + parcel->ReadInt64(&tv_sec); + time_stamp_.tv_sec = tv_sec & std::numeric_limits::max(); + + int64_t tv_nsec = 0; + parcel->ReadInt64(&tv_nsec); + time_stamp_.tv_nsec = tv_nsec & std::numeric_limits::max(); +} + +void ParcelHeader::SetTag(std::string tag) { + tag_ = std::move(tag); +} + +const std::string& ParcelHeader::GetTag() const { + return tag_; +} + +void ParcelHeader::SetSeqNum(int seq_num) { + seq_num_ = seq_num; +} + +int ParcelHeader::GetSeqNum() const { + return seq_num_; +} + +struct timespec ParcelHeader::GetTimeStamp() const { + return time_stamp_; +} + +int ParcelHeader::GenerateSeqNum() { + static std::atomic num { 0 }; + ++num; + return static_cast(num & INT_MAX); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/parcel-header-internal.hh b/src/rpc-port/parcel-header-internal.hh new file mode 100644 index 0000000..32a9007 --- /dev/null +++ b/src/rpc-port/parcel-header-internal.hh @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef PARCEL_HEADER_INTERNAL_H_ +#define PARCEL_HEADER_INTERNAL_H_ + +#include + +#include + +#include + +namespace rpc_port { +namespace internal { + +class ParcelHeader : public tizen_base::Parcelable { + public: + ParcelHeader(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + void SetTag(std::string tag); + const std::string& GetTag() const; + void SetSeqNum(int seq_num); + int GetSeqNum() const; + struct timespec GetTimeStamp() const; + + static int GenerateSeqNum(); + + private: + std::string tag_; + int seq_num_; + struct timespec time_stamp_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PARCEL_HEADER_INTERNAL_H_ diff --git a/src/rpc-port/parcel-internal.cc b/src/rpc-port/parcel-internal.cc new file mode 100644 index 0000000..932569c --- /dev/null +++ b/src/rpc-port/parcel-internal.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 "parcel-internal.hh" + +#include +#include + +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +Parcel::Parcel(bool without_header) + : header_(without_header ? nullptr : new ParcelHeader()) { +} + +Parcel::~Parcel() {} + +void Parcel::WriteToParcel(tizen_base::Parcel* parcel) const { + if (header_.get() != nullptr) { + parcel->WriteParcelable(*header_.get()); + parcel->WriteUInt32(handle_.GetDataSize()); + } + + parcel->Write(handle_.GetData(), handle_.GetDataSize()); +} + +void Parcel::ReadFromParcel(tizen_base::Parcel* parcel) { + if (header_.get() != nullptr) { + parcel->ReadParcelable(header_.get()); + + uint32_t size = 0; + parcel->ReadUInt32(&size); + if (size > 0) { + auto* buf = static_cast(malloc(size)); + if (buf == nullptr) { + _E("Out of memory"); // LCOV_EXEC_LINE + return; // LCOV_EXCL_LINE + } + + parcel->Read(buf, size); + handle_ = std::move(tizen_base::Parcel(buf, size, false)); + } + } else { + // LCOV_EXCL_START + handle_ = std::move( + tizen_base::Parcel(parcel->GetData(), parcel->GetDataSize())); + // LCOV_EXCL_STOP + } +} + +const ParcelHeader* Parcel::GetParcelHeader() { + return header_.get(); +} + +parcel_h Parcel::GetHandle() const { + return static_cast(const_cast(&handle_)); +} + +void Parcel::SetRawParcel(tizen_base::Parcel* raw_parcel) { + raw_parcel_.reset(raw_parcel); +} + +// LCOV_EXCL_START +tizen_base::Parcel* Parcel::GetRawParcel() const { + return raw_parcel_.get(); +} +// LCOV_EXCL_STOP + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/parcel-internal.hh b/src/rpc-port/parcel-internal.hh new file mode 100644 index 0000000..3d0911d --- /dev/null +++ b/src/rpc-port/parcel-internal.hh @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef PARCEL_INTERNAL_HH_ +#define PARCEL_INTERNAL_HH_ + +#include + +#include +#include + +#include + +#include "parcel-header-internal.hh" + +namespace rpc_port { +namespace internal { + +class Parcel : public tizen_base::Parcelable { + public: + Parcel(bool without_header = false); + ~Parcel(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + const ParcelHeader* GetParcelHeader(); + parcel_h GetHandle() const; + + void SetRawParcel(tizen_base::Parcel* raw_parcel); + tizen_base::Parcel* GetRawParcel() const; + + private: + std::unique_ptr header_; + tizen_base::Parcel handle_; + std::unique_ptr raw_parcel_ { nullptr }; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PARCEL_INTERNAL_HH_ diff --git a/src/rpc-port/peer-cred-internal.cc b/src/rpc-port/peer-cred-internal.cc new file mode 100644 index 0000000..150d3ab --- /dev/null +++ b/src/rpc-port/peer-cred-internal.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 +#include + +#include + +#include "log-private.hh" +#include "peer-cred-internal.hh" + +namespace rpc_port { +namespace internal { + +PeerCred::PeerCred(pid_t pid, uid_t uid, gid_t gid) + : pid_(pid), uid_(uid), gid_(gid) { +} + +PeerCred* PeerCred::Get(int fd) { + struct ucred cred; + socklen_t len = static_cast(sizeof(struct ucred)); + int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, + static_cast(&cred), &len); + if (ret != 0) { + _E("getsockopt() is failed. fd(%d), errno(%d)", fd, errno); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE + } + + return new (std::nothrow) PeerCred(cred.pid, cred.uid, cred.gid); +} + +pid_t PeerCred::GetPid() const { + return pid_; +} + +uid_t PeerCred::GetUid() const { + return uid_; +} + + +// LCOV_EXCL_START +gid_t PeerCred::GetGid() const { + return gid_; +} +// LCOV_EXCL_STOP + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/peer-cred-internal.hh b/src/rpc-port/peer-cred-internal.hh new file mode 100644 index 0000000..bf57ed5 --- /dev/null +++ b/src/rpc-port/peer-cred-internal.hh @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef PEER_CRED_INTERNAL_HH_ +#define PEER_CRED_INTERNAL_HH_ + +namespace rpc_port { +namespace internal { + +class PeerCred { + public: + static PeerCred* Get(int fd); + + pid_t GetPid() const; + uid_t GetUid() const; + gid_t GetGid() const; + + private: + PeerCred(pid_t pid, uid_t uid, gid_t gid); + + private: + pid_t pid_; + uid_t uid_; + gid_t gid_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PEER_CRED_INTERNAL_HH_ diff --git a/src/rpc-port/port-internal.cc b/src/rpc-port/port-internal.cc new file mode 100644 index 0000000..c32d5fb --- /dev/null +++ b/src/rpc-port/port-internal.cc @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2017 - 2021 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "include/rpc-port.h" +#include "log-private.hh" +#include "message-sending-thread-internal.hh" +#include "port-internal.hh" + +namespace rpc_port { +namespace internal { +namespace { + +constexpr const int QUEUE_SIZE_MAX = 1024 * 1024 * 10; +constexpr const int MAX_RETRY_CNT = 10; +constexpr const int MAX_TIMEOUT = 1000; +constexpr const int MIN_TIMEOUT = 50; + +} // namespace + +// LCOV_EXCL_START +Port::DelayMessage::DelayMessage(const char* msg, int index, int size) + : message_(msg, msg + size), index_(index), size_(size) { +} + +void Port::DelayMessage::SetIndex(int index) { + index_ += index; +} + +int Port::DelayMessage::GetSize() { + return size_ - index_; +} + +int Port::DelayMessage::GetOriginalSize() { + return size_; +} + +char* Port::DelayMessage::GetMessage() { + char* ptr = reinterpret_cast(message_.data()); + ptr += index_; + return ptr; +} +// LCOV_EXCL_STOP + +Port::Port(int fd, std::string id) + : fd_(fd), id_(std::move(id)), instance_(""), seq_(0) { + char uuid[37]; + uuid_t u; + uuid_generate(u); + uuid_unparse(u, uuid); + instance_ = std::string(uuid) + ":" + id_; + SetReceiveTimeout(10000); +} + +Port::Port(int fd, std::string id, std::string instance) + : fd_(fd), id_(std::move(id)), instance_(std::move(instance)), seq_(0) { + SetReceiveTimeout(10000); +} + +Port::~Port() { + std::lock_guard lock(mutex_); + ClearQueue(); + Disconnect(); +} + +void Port::Disconnect() { + IgnoreIOEvent(); + + std::lock_guard lock(rw_mutex_); + if (fd_ > 0) { + _W("Close fd(%d)", fd_); + close(fd_); + fd_ = -1; + } +} + +int Port::SetPrivateSharing(const char* paths[], unsigned int size) { + int ret = aul_rpc_port_set_private_sharing(id_.c_str(), paths, size); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +int Port::SetPrivateSharing(const char* path) { + const char* file_list[1] = {path}; + int ret = aul_rpc_port_set_private_sharing(id_.c_str(), file_list, 1); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + return RPC_PORT_ERROR_NONE; +} + +int Port::UnsetPrivateSharing() { + int ret = aul_rpc_port_unset_private_sharing(id_.c_str()); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + return RPC_PORT_ERROR_NONE; +} + +int Port::Read(void* buf, unsigned int size) { + unsigned int left = size; + ssize_t nb; + int bytes_read = 0; + char* buffer = static_cast(buf); + int flags; + + std::lock_guard lock(rw_mutex_); + if (fd_ < 0 || fd_ >= sysconf(_SC_OPEN_MAX)) { + _E("Invalid fd(%d)", fd_); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + flags = fcntl(fd_, F_GETFL, 0); + fcntl(fd_, F_SETFL, flags & ~O_NONBLOCK); + + while (left) { + nb = read(fd_, buffer, left); + if (nb == 0) { + _E("read_socket: ...read EOF, socket closed %d: nb %zd\n", fd_, nb); + fcntl(fd_, F_SETFL, flags); + return RPC_PORT_ERROR_IO_ERROR; + } + + if (nb == -1) { + if (errno == EINTR) { + usleep(100 * 1000); + continue; + } + + _E("read_socket: ...error fd %d: errno %d\n", fd_, errno); + fcntl(fd_, F_SETFL, flags); + return RPC_PORT_ERROR_IO_ERROR; + } + + left -= nb; + buffer += nb; + bytes_read += nb; + } + + fcntl(fd_, F_SETFL, flags); + return RPC_PORT_ERROR_NONE; +} + +// LCOV_EXCL_START +int Port::SetReceiveTimeout(int timeout) { + if (timeout == INT_MAX) + return -EINVAL; + + if (timeout == -1) + timeout = 10000; + + if (timeout < 0) { + _E("Invalid parameter"); + return -EINVAL; + } + + struct timeval tv = { + .tv_sec = static_cast(timeout / 1000), + .tv_usec = static_cast((timeout % 1000) * 1000) + }; + socklen_t len = static_cast(sizeof(struct timeval)); + int ret = setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &tv, len); + if (ret < 0) { + ret = -errno; + _E("setsockopt() is failed. errno(%d)", errno); + } + + return ret; +} + +bool Port::CanWrite() { + struct pollfd fds[1]; + fds[0].fd = fd_; + fds[0].events = POLLOUT; + fds[0].revents = 0; + int ret = poll(fds, 1, 100); + if (ret <= 0) { + _W("poll() is failed. fd(%d), error(%s)", + fd_, ret == 0 ? "timed out" : std::to_string(-errno).c_str()); + return false; + } + + return true; +} +// LCOV_EXCL_STOP + +int Port::Write(const void* buf, unsigned int size) { + int sent_bytes = 0; + int ret; + std::lock_guard lock(rw_mutex_); + + if (queue_.empty()) { + ret = Write(buf, size, &sent_bytes); + if (ret == PORT_STATUS_ERROR_NONE) + return RPC_PORT_ERROR_NONE; + else if (ret == PORT_STATUS_ERROR_IO_ERROR) + return RPC_PORT_ERROR_IO_ERROR; + } else if (CanWrite()) { // LCOV_EXCL_LINE + // LCOV_EXCL_START + while (!queue_.empty()) { + int port_status = PopDelayedMessage(); + if (port_status != PORT_STATUS_ERROR_NONE) { + if (port_status == PORT_STATUS_ERROR_IO_ERROR) + return RPC_PORT_ERROR_IO_ERROR; + + break; + } + } + // LCOV_EXCL_STOP + } + + // LCOV_EXCL_START + if (delayed_message_size_ > QUEUE_SIZE_MAX) { + _E("cache fail : delayed_message_size (%d), count(%zu)", + delayed_message_size_, queue_.size()); + return RPC_PORT_ERROR_IO_ERROR; + } + + return PushDelayedMessage( + std::make_shared( + static_cast(buf), sent_bytes, size)); + // LCOV_EXCL_STOP +} + +int Port::Write(const void* buf, unsigned int size, int* sent_bytes) { + unsigned int left = size; + ssize_t nb; + int retry_cnt = 0; + const char* buffer = static_cast(buf); + + if (fd_ < 0 || fd_ >= sysconf(_SC_OPEN_MAX)) { + _E("Invalid fd(%d)", fd_); // LCOV_EXCL_LINE + return PORT_STATUS_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + while (left && (retry_cnt < MAX_RETRY_CNT)) { + nb = send(fd_, buffer, left, MSG_NOSIGNAL); + if (nb == -1) { + if (errno == EINTR) { + // LCOV_EXCL_START + LOGI("write_socket: EINTR continue ..."); + retry_cnt++; + continue; + // LCOV_EXCL_STOP + } + + if (errno == EAGAIN || errno == EWOULDBLOCK) + return PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE; + + _E("write_socket: ...error fd: %d, errno: %d", fd_, errno); + return PORT_STATUS_ERROR_IO_ERROR; + } + + left -= nb; + buffer += nb; + *sent_bytes += nb; + } + + if (left != 0) { + _E("error fd %d: retry_cnt %d", fd_, retry_cnt); + return PORT_STATUS_ERROR_IO_ERROR; + } + + return PORT_STATUS_ERROR_NONE; +} + +// LCOV_EXCL_START +gboolean Port::OnEventReceived(GIOChannel* io, GIOCondition condition, + gpointer data) { + auto* ptr = static_cast*>(data); + auto port = ptr->lock(); + if (port == nullptr) { + _E("port is destructed"); + return G_SOURCE_REMOVE; + } + + _W("Writing is now possible. fd: %d, id: %s", + port->GetFd(), port->GetId().c_str()); + std::lock_guard lock(port->rw_mutex_); + if (port->source_id_ == 0) { + _E("GSource is destroyed"); + return G_SOURCE_REMOVE; + } + + if (port->queue_.empty()) { + port->IgnoreIOEvent(); + return G_SOURCE_CONTINUE; + } + + port->PopDelayedMessage(); + return G_SOURCE_CONTINUE; +} +// LCOV_EXCL_STOP + +void Port::ClearQueue() { + std::lock_guard lock(rw_mutex_); + + while (queue_.empty() == false) + queue_.pop(); + + IgnoreIOEvent(); + delayed_message_size_ = 0; +} + +void Port::IgnoreIOEvent() { + std::lock_guard lock(rw_mutex_); + if (source_id_ != 0) { + // LCOV_EXCL_START + GSource* source = g_main_context_find_source_by_id( + MessageSendingThread::GetInst().GetContext(), source_id_); + if (source != nullptr && !g_source_is_destroyed(source)) + g_source_destroy(source); + + source_id_ = 0; + // LCOV_EXCL_STOP + } + + if (channel_ != nullptr) { + g_io_channel_unref(channel_); // LCOV_EXCL_LINE + channel_ = nullptr; // LCOV_EXCL_LINE + } +} + +// LCOV_EXCL_START +int Port::ListenIOEvent() { + std::lock_guard lock(rw_mutex_); + channel_ = g_io_channel_unix_new(fd_); + if (channel_ == nullptr) { + _E("Failed to create GIOChannel"); + return RPC_PORT_ERROR_OUT_OF_MEMORY; + } + + GSource* source = g_io_create_watch(channel_, + static_cast(G_IO_OUT)); + if (source == nullptr) { + _E("Failed to create GSource"); + IgnoreIOEvent(); + return RPC_PORT_ERROR_OUT_OF_MEMORY; + } + + auto* ptr = new (std::nothrow) std::weak_ptr(shared_from_this()); + g_source_set_callback(source, reinterpret_cast(OnEventReceived), + static_cast(ptr), [](gpointer ptr) { + auto* port = static_cast*>(ptr); + delete port; + }); + g_source_set_priority(source, G_PRIORITY_DEFAULT); + source_id_ = g_source_attach(source, + MessageSendingThread::GetInst().GetContext()); + g_source_unref(source); + + return RPC_PORT_ERROR_NONE; +} + +int Port::PopDelayedMessage() { + int sent_bytes = 0; + std::lock_guard lock(rw_mutex_); + auto dm = queue_.front(); + + int ret = Write(dm->GetMessage(), dm->GetSize(), &sent_bytes); + if (ret == PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE) { + dm->SetIndex(sent_bytes); + } else if (ret == PORT_STATUS_ERROR_IO_ERROR) { + ClearQueue(); + } else { + delayed_message_size_ -= dm->GetOriginalSize(); + queue_.pop(); + } + + _W("cache : count(%zu), delayed_message_size(%d), ret(%d), sent_bytes(%d)", + queue_.size(), delayed_message_size_, ret, sent_bytes); + return ret; +} + +int Port::PushDelayedMessage(std::shared_ptr dm) { + std::lock_guard lock(rw_mutex_); + if (queue_.empty()) { + int ret = ListenIOEvent(); + if (ret != RPC_PORT_ERROR_NONE) + return ret; + } + + delayed_message_size_ += dm->GetOriginalSize(); + queue_.push(dm); + + _W("cache : count(%zu), delayed_message_size(%d)", + queue_.size(), delayed_message_size_); + return RPC_PORT_ERROR_NONE; +} +// LCOV_EXCL_STOP + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/port-internal.hh b/src/rpc-port/port-internal.hh new file mode 100644 index 0000000..64d33ec --- /dev/null +++ b/src/rpc-port/port-internal.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef PORT_INTERNAL_HH_ +#define PORT_INTERNAL_HH_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rpc_port { +namespace internal { + +class Port : public std::enable_shared_from_this { + public: + Port(int fd, std::string id, std::string instance); + Port(int fd, std::string id); + virtual ~Port(); + + void Disconnect(); + int SetPrivateSharing(const char* paths[], unsigned int size); + int SetPrivateSharing(const char* path); + int UnsetPrivateSharing(); + + int Read(void* buf, unsigned int size); + int Write(const void* buf, unsigned int size); + int Write(const void* buf, unsigned int size, int* sent_bytes); + int GetFd() const { + return fd_; + } + + const std::string& GetId() const { + return id_; + } + + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + const std::string& GetInstance() const { + return instance_; + } + + uint32_t GetSeq() { + return ++seq_; + } + + private: + // LCOV_EXCL_START + int SetReceiveTimeout(int timeout); + bool CanWrite(); + void IgnoreIOEvent(); + int ListenIOEvent(); + + class DelayMessage { + public: + DelayMessage(const char* msg, int start_index, int size); + ~DelayMessage() = default; + void SetIndex(int index); + int GetSize(); + int GetOriginalSize(); + char* GetMessage(); + + private: + std::vector message_; + int index_; + int size_; + }; + + enum PortStatus { + PORT_STATUS_ERROR_NONE, + PORT_STATUS_ERROR_IO_ERROR, + PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE + }; + + int PushDelayedMessage(std::shared_ptr dm); + int PopDelayedMessage(); + static gboolean OnEventReceived(GIOChannel* io, + GIOCondition condition, gpointer data); + void ClearQueue(); + // LCOV_EXCL_STOP + + int fd_; + std::string id_; + std::string instance_; + std::atomic seq_; + mutable std::recursive_mutex mutex_; + mutable std::recursive_mutex rw_mutex_; + std::queue> queue_; + int delayed_message_size_ = 0; + GIOChannel* channel_ = nullptr; + guint source_id_ = 0; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PORT_INTERNAL_HH_ diff --git a/src/rpc-port/proxy-internal.cc b/src/rpc-port/proxy-internal.cc new file mode 100644 index 0000000..cd52cd6 --- /dev/null +++ b/src/rpc-port/proxy-internal.cc @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2017 - 2021 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 +#include +#include +#include +#include + +#include +#include +#include + +#include "aul-internal.hh" +#include "debug-port-internal.hh" +#include "exception-internal.hh" +#include "include/rpc-port-internal.h" +#include "log-private.hh" +#include "proxy-internal.hh" +#include "request-internal.hh" +#include "response-internal.hh" + +#define EILLEGALACCESS 127 + +namespace rpc_port { +namespace internal { +namespace { + +constexpr const char kPortTypeMain[] = "main"; +constexpr const char kPortTypeDelegate[] = "delegate"; +constexpr const char kDPrefix[] = "d::"; +constexpr const char kUdPrefix[] = "ud::"; + +std::string GenInstance() { + uuid_t u; + uuid_generate(u); + char uuid[37]; + uuid_unparse(u, uuid); + return std::string(uuid) + "@" + Aul::GetAppId(getpid()); +} + +int SendRequest(ClientSocket* client, const Request& request) { + tizen_base::Parcel parcel; + parcel.WriteParcelable(const_cast(request)); + size_t size = parcel.GetDataSize(); + int ret = client->Send(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + ret = client->Send(parcel.GetData(), size); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +int ReceiveResponse(ClientSocket* client, Response** response) { + int flags = fcntl(client->GetFd(), F_GETFL, 0); + fcntl(client->GetFd(), F_SETFL, flags & ~O_NONBLOCK); + + size_t size = 0; + int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + // LCOV_EXCL_START + _E("Receive() is failed. error(%d)", ret); + fcntl(client->GetFd(), F_SETFL, flags); + return -1; + // LCOV_EXCL_STOP + } + + uint8_t* buf = static_cast(malloc(size)); + if (buf == nullptr) { + // LCOV_EXCL_START + _E("Out of memory"); + fcntl(client->GetFd(), F_SETFL, flags); + return -1; + // LCOV_EXCL_STOP + } + + ret = client->Receive(buf, size); + if (ret != 0) { + // LCOV_EXCL_START + _E("Receive() is failed. error(%d)", ret); + free(buf); + fcntl(client->GetFd(), F_SETFL, flags); + return -1; + // LCOV_EXCL_STOP + } + + tizen_base::Parcel parcel(buf, size, false); + *response = new (std::nothrow) Response(); + if (*response == nullptr) { + // LCOV_EXCL_START + _E("Out of memory"); + fcntl(client->GetFd(), F_SETFL, flags); + return -1; + // LCOV_EXCL_STOP + } + + parcel.ReadParcelable(*response); + fcntl(client->GetFd(), F_SETFL, flags); + return 0; +} + +bool IsDaemon(const std::string& name) { + if (name.compare(0, strlen(kDPrefix), kDPrefix) == 0) return true; + + if (name.compare(0, strlen(kUdPrefix), kUdPrefix) == 0) return true; + + return false; +} + +} // namespace + +Proxy::Proxy() { + _D("Proxy::Proxy()"); +} + +Proxy::~Proxy() { + std::lock_guard lock(GetMutex()); + _D("Proxy::~Proxy()"); + if (main_port_.get() != nullptr) + DebugPort::RemoveSession(main_port_->GetFd()); // LCOV_EXCL_LINE + + listener_ = nullptr; + UnsetIdler(); + UnsetConnTimer(); + Cancel(); +} + +int Proxy::MainPortConnect(const std::string& instance, bool sync) { + std::lock_guard lock(GetMutex()); + fds_[0] = 0; + main_client_.reset(Client::Create(this, port_path_)); + if (main_client_.get() == nullptr) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + Request request(instance.c_str(), kPortTypeMain); + int ret = SendRequest(main_client_.get(), request); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + main_client_->SetNonblock(); + if (sync) { + Response* response = nullptr; + ret = ReceiveResponse(main_client_.get(), &response); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE + } + + fds_[0] = main_client_->RemoveFd(); + } else { + ret = main_client_->Watch(); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + return RPC_PORT_ERROR_NONE; +} + +int Proxy::DelegatePortConnect(const std::string& instance, bool sync) { + std::lock_guard lock(GetMutex()); + fds_[1] = 0; + delegate_client_.reset(Client::Create(this, port_path_)); + if (delegate_client_.get() == nullptr) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + Request request(instance.c_str(), kPortTypeDelegate); + int ret = SendRequest(delegate_client_.get(), request); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + delegate_client_->SetNonblock(); + if (sync) { + Response* response = nullptr; + ret = ReceiveResponse(delegate_client_.get(), &response); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE + } + + fds_[1] = delegate_client_->RemoveFd(); + } else { + ret = delegate_client_->Watch(); + if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + return RPC_PORT_ERROR_NONE; +} + +int Proxy::Connect(bool sync) { + std::lock_guard lock(GetMutex()); + std::string instance = GenInstance(); + int ret = MainPortConnect(instance, sync); + if (ret != RPC_PORT_ERROR_NONE) return ret; + + ret = DelegatePortConnect(instance, sync); + if (ret != RPC_PORT_ERROR_NONE) return ret; + + if (sync) { + main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); + delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); + DebugPort::AddSession(port_name_, target_appid_, fds_[0], fds_[1]); + listener_->OnConnected(target_appid_, main_port_.get()); + } + + return ret; +} + +int Proxy::Connect(std::string appid, std::string port_name, + IEventListener* listener) { + if (listener == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + std::lock_guard lock(GetMutex()); + if (HasRequested()) { + _D("Already requested"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE + } + + listener_ = listener; + target_appid_ = std::move(appid); + port_name_ = std::move(port_name); + SetRealAppId(target_appid_); + main_port_.reset(); + delegate_port_.reset(); + port_path_ = + Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid()); + + Cancel(); + UnsetConnTimer(); + if (!IsDaemon(real_appid_)) { + int ret = Aul::PrepareStub(real_appid_, port_name_, + rpc_port_get_target_uid()); + if (ret != RPC_PORT_ERROR_NONE) { + listener_ = nullptr; + return ret; + } + } + + if (Watch() != 0) { + listener_ = nullptr; // LCOV_EXCL_LINE + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + return RPC_PORT_ERROR_NONE; +} + +int Proxy::ConnectSync(std::string appid, std::string port_name, + IEventListener* listener) { + if (listener == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + std::lock_guard lock(GetMutex()); + if (HasRequested()) { + _D("Already requested"); + return RPC_PORT_ERROR_INVALID_PARAMETER; + } + + listener_ = listener; + target_appid_ = std::move(appid); + port_name_ = std::move(port_name); + SetRealAppId(target_appid_); + port_path_ = + Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid()); + + if (!IsDaemon(real_appid_)) { + int ret = Aul::PrepareStub(real_appid_, port_name_, + rpc_port_get_target_uid()); + if (ret != RPC_PORT_ERROR_NONE) { + listener_ = nullptr; + return ret; + } + } + + if (!WaitUntilPortCreation()) + return RPC_PORT_ERROR_IO_ERROR; + + int ret = Connect(true); + if (ret != RPC_PORT_ERROR_NONE) { + // LCOV_EXCL_START + listener_ = nullptr; + return ret; + // LCOV_EXCL_STOP + } + + return RPC_PORT_ERROR_NONE; +} + +bool Proxy::WaitUntilPortCreation() { + file_monitor_.reset(new FileMonitor(port_path_)); + int retry_count = 100; + do { + if (file_monitor_->Exist()) return true; + + usleep(100 * 1000); + retry_count--; + } while (retry_count > 0); + + if (!file_monitor_->Exist()) { + // LCOV_EXCL_START + _E("port(%s) of appid(%s) is not ready", + port_name_.c_str(), target_appid_.c_str()); + return false; + // LCOV_EXCL_STOP + } + + return true; +} + +void Proxy::DisconnectPort() { + std::lock_guard lock(GetMutex()); + if (main_port_.get() != nullptr) { + DebugPort::RemoveSession(main_port_->GetFd()); + main_port_.reset(); + } +} + +int Proxy::Watch() { + std::lock_guard lock(GetMutex()); + try { + file_monitor_.reset(new FileMonitor(port_path_, this)); + file_monitor_->Start(); + SetConnTimer(); + SetIdler(); + } catch (const Exception& e) { + LOGE("Exception occurs. error(%s)", e.what()); + return -1; + } + + return 0; +} + +void Proxy::Cancel() { + std::lock_guard lock(GetMutex()); + if (!file_monitor_) return; + + file_monitor_->Stop(); +} + +void Proxy::SetRealAppId(const std::string& alias_appid) { + std::lock_guard lock(GetMutex()); + if (!real_appid_.empty()) + return; + + if (IsDaemon(alias_appid)) { + real_appid_ = alias_appid; + return; + } + + char* appid = nullptr; + int ret = aul_svc_get_appid_by_alias_appid(alias_appid.c_str(), &appid); + if (ret != AUL_SVC_RET_OK) { + real_appid_ = alias_appid; + return; + } + + // LCOV_EXCL_START + std::unique_ptr appid_ptr(appid, std::free); + real_appid_ = std::string(appid); + _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid); + // LCOV_EXCL_STOP +} + +std::recursive_mutex& Proxy::GetMutex() const { + return mutex_; +} + +void Proxy::SetConnTimer() { + if (conn_timer_data_) { + _W("Already exists"); // LCOV_EXCL_START + return; // LCOV_EXCL_START + } + + conn_timer_data_ = CreateWeakPtr(); + if (conn_timer_data_ == nullptr) { + _E("Out of memory"); // LCOV_EXCL_START + return; // LCOV_EXCL_START + } + + g_timeout_add_seconds(10, OnTimedOut, conn_timer_data_); +} + +void Proxy::UnsetConnTimer() { + if (conn_timer_data_ == nullptr) + return; + + GSource* source = g_main_context_find_source_by_user_data(nullptr, + conn_timer_data_); + if (source && !g_source_is_destroyed(source)) + g_source_destroy(source); + + DestroyWeakPtr(conn_timer_data_); + conn_timer_data_ = nullptr; +} + +void Proxy::SetIdler() { + if (idler_data_) { + _W("Already exists"); // LCOV_EXCL_START + return; // LCOV_EXCL_START + } + + idler_data_ = CreateWeakPtr(); + if (idler_data_ == nullptr) { + _E("Out of memory"); // LCOV_EXCL_START + return; // LCOV_EXCL_START + } + + g_idle_add(OnIdle, idler_data_); +} + +void Proxy::UnsetIdler() { + if (idler_data_ == nullptr) + return; + + GSource* source = g_main_context_find_source_by_user_data(nullptr, + idler_data_); + if (source && !g_source_is_destroyed(source)) + g_source_destroy(source); + + DestroyWeakPtr(idler_data_); + idler_data_ = nullptr; +} + +void Proxy::OnFileCreated(const std::string& path) { + _W("appid=%s, port_name=%s, port_path=%s", + target_appid_.c_str(), port_name_.c_str(), path.c_str()); + std::lock_guard lock(GetMutex()); + UnsetIdler(); + Cancel(); + if (listener_ == nullptr) return; // LCOV_EXCL_LINE + + int ret = Connect(false); + if (ret != RPC_PORT_ERROR_NONE) { + // LCOV_EXCL_START + UnsetConnTimer(); + auto* listener = listener_; + listener_ = nullptr; + if (ret == RPC_PORT_ERROR_PERMISSION_DENIED) + listener->OnRejected(target_appid_, ret); + else + listener->OnDisconnected(target_appid_); + // LCOV_EXCL_STOP + } +} + +void Proxy::OnFileDeleted(const std::string& path) { + _W("appid=%s, port_name=%s, port_path=%s", + target_appid_.c_str(), port_name_.c_str(), path.c_str()); + std::lock_guard lock(GetMutex()); + UnsetIdler(); +} + +gboolean Proxy::OnTimedOut(gpointer user_data) { + _E("Timed out"); + auto* ptr = static_cast*>(user_data); + auto proxy = ptr->lock(); + if (proxy == nullptr) { + _E("Proxy is nullptr"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + std::lock_guard lock(proxy->GetMutex()); + if (proxy->conn_timer_data_ == nullptr) { + _E("Invalid context. proxy(%p)", proxy.get()); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + proxy->Cancel(); + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + DestroyWeakPtr(proxy->conn_timer_data_); + proxy->conn_timer_data_ = nullptr; + + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + proxy->listener_ = nullptr; + listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); + return G_SOURCE_REMOVE; +} + +gboolean Proxy::OnIdle(gpointer user_data) { + auto* ptr = static_cast*>(user_data); + auto proxy = ptr->lock(); + if (proxy == nullptr) { + _E("Proxy is nullptr"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + std::lock_guard lock(proxy->GetMutex()); + if (proxy->idler_data_ == nullptr) { + _E("Invalid context. proxy(%p)", proxy.get()); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + DestroyWeakPtr(proxy->idler_data_); + proxy->idler_data_ = nullptr; + + if (proxy->file_monitor_->Exist()) { + proxy->OnFileCreated(proxy->port_path_); + } else { + proxy->OnFileDeleted(proxy->port_path_); + } + + return G_SOURCE_REMOVE; +} + +Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, + bool receive) + : Port(fd, id), parent_(parent) { + Watch(receive); +} + +Proxy::ProxyPort::~ProxyPort() { + if (disconn_source_ > 0) + g_source_remove(disconn_source_); + + if (source_ > 0) + g_source_remove(source_); + + if (channel_ != nullptr) + g_io_channel_unref(channel_); +} + +int Proxy::ProxyPort::Watch(bool receive) { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + disconn_source_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + Proxy::ProxyPort::OnSocketDisconnected, parent_); + if (disconn_source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + if (!receive) + return 0; + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + Proxy::ProxyPort::OnDataReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +void Proxy::ProxyPort::SetDisconnectedSource(guint source_id) { + disconn_source_ = source_id; +} + +void Proxy::ProxyPort::SetSource(guint source_id) { + source_ = source_id; +} + +gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + int fd = g_io_channel_unix_get_fd(channel); + _W("Socket was disconnected. fd(%d)", fd); + if (proxy->main_port_.get() != nullptr && + proxy->main_port_->GetFd() == fd) { + proxy->main_port_->SetDisconnectedSource(0); + } else if (proxy->delegate_port_.get() != nullptr && + proxy->delegate_port_->GetFd() == fd) { + proxy->delegate_port_->SetDisconnectedSource(0); + } + + proxy->main_port_.reset(); + proxy->delegate_port_.reset(); + proxy->listener_ = nullptr; + listener->OnDisconnected(proxy->target_appid_); + DebugPort::RemoveSession(fd); + return G_SOURCE_REMOVE; +} + +gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + int fd = g_io_channel_unix_get_fd(channel); + if (proxy->delegate_port_->GetFd() == fd) { + char buffer[4]; + if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { + _W("Socket was disconnected by stub. fd(%d)", fd); + proxy->listener_ = nullptr; + proxy->delegate_port_->SetSource(0); + if (proxy->main_port_.get() != nullptr) { + DebugPort::RemoveSession(proxy->main_port_->GetFd()); + proxy->main_port_.reset(); + } + proxy->delegate_port_.reset(); + listener->OnDisconnected(proxy->target_appid_); + return G_SOURCE_REMOVE; + } + + listener->OnReceived(proxy->target_appid_); + } + + return G_SOURCE_CONTINUE; +} + +Proxy::Client::Client(Proxy* parent) : parent_(parent) { +} + +Proxy::Client::~Client() { + if (channel_) + g_io_channel_unref(channel_); + + if (disconn_source_ > 0) + g_source_remove(disconn_source_); + + if (source_ > 0) + g_source_remove(source_); +} + +Proxy::Client* Proxy::Client::Create(Proxy* parent, + const std::string& endpoint) { + std::unique_ptr client; + try { + client.reset(new (std::nothrow) Proxy::Client(parent)); + } catch (const Exception& e) { + _E("Exception(%s) occurs", e.what()); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE + } + + int ret; + int retry_count = 5; + do { + ret = client->Connect(endpoint); + if (ret == 0) { + break; + } else if (ret < 0) { + // LCOV_EXCL_START + _D("Connect() is failed"); + usleep(100 * 1000); + retry_count--; + // LCOV_EXCL_STOP + } + } while (retry_count > 0); + + if (ret != 0) { + _E("Connect() is failed"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE + } + + try { + client->SetReceiveTimeout(10000); + } catch (const Exception& e) { + _E("Exception occurs. error(%s)", e.what()); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE + } + + _W("endpoint(%s), fd(%d)", endpoint.c_str(), client->GetFd()); + return client.release(); +} + +int Proxy::Client::Watch() { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + Proxy::Client::OnResponseReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + disconn_source_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + Proxy::Client::OnSocketDisconnected, parent_); + if (disconn_source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +// LCOV_EXCL_START +void Proxy::Client::SetDisconnectedSource(guint source) { + disconn_source_ = source; +} +// LCOV_EXCL_STOP + +void Proxy::Client::SetSource(guint source) { + source_ = source; +} + +// LCOV_EXCL_START +gboolean Proxy::Client::OnSocketDisconnected(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + proxy->UnsetConnTimer(); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + int fd = g_io_channel_unix_get_fd(channel); + _W("Socket was disconnected. fd(%d)", fd); + if (proxy->main_client_.get() != nullptr && + proxy->main_client_->GetFd() == fd) { + proxy->main_client_->SetDisconnectedSource(0); + } else if (proxy->delegate_client_.get() != nullptr && + proxy->delegate_client_->GetFd() == fd) { + proxy->delegate_client_->SetDisconnectedSource(0); + } + + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + proxy->listener_ = nullptr; + listener->OnDisconnected(proxy->target_appid_); + return G_SOURCE_REMOVE; +} +// LCOV_EXCL_STOP + +gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + proxy->UnsetConnTimer(); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + bool is_delegate = false; + std::unique_ptr client; + int fd = g_io_channel_unix_get_fd(channel); + if (proxy->main_client_.get() != nullptr && + proxy->main_client_->GetFd() == fd) { + client.reset(proxy->main_client_.release()); + } else if (proxy->delegate_client_.get() != nullptr && + proxy->delegate_client_->GetFd() == fd) { + client.reset(proxy->delegate_client_.release()); + is_delegate = true; + } + + if (client.get() == nullptr) { + _E("Unknown fd(%d)", fd); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + client->SetSource(0); + + Response* response = nullptr; + int ret = ReceiveResponse(client.get(), &response); + if (ret != 0) { + // LCOV_EXCL_START + proxy->listener_ = nullptr; + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); + return G_SOURCE_REMOVE; + // LCOV_EXCL_STOP + } + + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); + proxy->listener_ = nullptr; + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + listener->OnRejected(proxy->target_appid_, + RPC_PORT_ERROR_PERMISSION_DENIED); + return G_SOURCE_REMOVE; + } + + client->SetNonblock(); + int client_fd = client->RemoveFd(); + if (is_delegate) { + _W("[DELEGATE] Result received"); + proxy->fds_[1] = client_fd; + proxy->delegate_port_.reset( + new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_)); + } else { + _W("[MAIN] Result received"); + proxy->fds_[0] = client_fd; + proxy->main_port_.reset( + new ProxyPort(proxy, proxy->fds_[0], proxy->target_appid_, false)); + } + + if (proxy->main_port_.get() != nullptr && + proxy->delegate_port_.get() != nullptr) { + _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)", + proxy->target_appid_.c_str(), proxy->port_name_.c_str(), + proxy->fds_[0], proxy->fds_[1]); + + DebugPort::AddSession(proxy->port_name_, proxy->target_appid_, + proxy->fds_[0], proxy->fds_[1]); + listener->OnConnected(proxy->target_appid_, proxy->main_port_.get()); + } + + return G_SOURCE_REMOVE; +} + +std::shared_ptr Proxy::GetSharedPtr() { + return shared_from_this(); +} + +gpointer Proxy::CreateWeakPtr() { + auto* ptr = new (std::nothrow) std::weak_ptr(GetSharedPtr()); + return static_cast(ptr); +} + +void Proxy::DestroyWeakPtr(gpointer data) { + auto* ptr = static_cast*>(data); + delete ptr; +} + +bool Proxy::HasRequested() const { + return listener_ != nullptr && + (!main_port_ || !delegate_port_ || main_port_->GetFd() > 0); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/proxy-internal.hh b/src/rpc-port/proxy-internal.hh new file mode 100644 index 0000000..2ef4dcc --- /dev/null +++ b/src/rpc-port/proxy-internal.hh @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef PROXY_INTERNAL_HH_ +#define PROXY_INTERNAL_HH_ + +#include +#include +#include +#include + +#include +#include +#include + +#include "client-socket-internal.hh" +#include "file-monitor-internal.hh" +#include "port-internal.hh" + +namespace rpc_port { +namespace internal { + +class Proxy : public std::enable_shared_from_this, + public FileMonitor::IEvent { + public: + Proxy(); + virtual ~Proxy(); + + class IEventListener { + public: + virtual void OnConnected(const std::string& endpoint, Port* port) = 0; + virtual void OnDisconnected(const std::string& endpoint) = 0; + virtual void OnRejected(const std::string& endpoint, int err_code) = 0; + virtual void OnReceived(const std::string& endpoint) = 0; + }; + + int Connect(std::string appid, std::string port_name, IEventListener* ev); + int ConnectSync(std::string appid, std::string port_name, IEventListener* ev); + void DisconnectPort(); + + std::shared_ptr GetPort() const { + return main_port_; + } + + std::shared_ptr GetDelegatePort() const { + return delegate_port_; + } + + const std::string& GetPortName() { + return port_name_; + } + + private: + class ProxyPort : public Port { + public: + ProxyPort(Proxy* parent, int fd, const std::string& id, + bool receive = true); + virtual ~ProxyPort(); + void SetDisconnectedSource(guint source_id); + void SetSource(guint source_id); + + private: + int Watch(bool receive); + + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + Proxy* parent_ = nullptr; + GIOChannel* channel_ = nullptr; + guint disconn_source_ = 0; + guint source_ = 0; + }; + + class Client : public ClientSocket { + public: + explicit Client(Proxy* parent); + virtual ~Client(); + + static Client* Create(Proxy* parent, const std::string& endpoint); + + int Watch(); + void SetDisconnectedSource(guint source); + void SetSource(guint source); + + private: + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnResponseReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + Proxy* parent_; + GIOChannel* channel_ = nullptr; + guint disconn_source_ = 0; + guint source_ = 0; + }; + + private: + void OnFileCreated(const std::string& path) override; + void OnFileDeleted(const std::string& path) override; + static gboolean OnTimedOut(gpointer user_data); + static gboolean OnIdle(gpointer user_data); + + void SetRealAppId(const std::string& alias_appid); + std::recursive_mutex& GetMutex() const; + int MainPortConnect(const std::string& instance, bool sync); + int DelegatePortConnect(const std::string& instance, bool sync); + int Connect(bool sync); + bool WaitUntilPortCreation(); + int Watch(); + void Cancel(); + void SetConnTimer(); + void UnsetConnTimer(); + void SetIdler(); + void UnsetIdler(); + + std::shared_ptr GetSharedPtr(); + gpointer CreateWeakPtr(); + static void DestroyWeakPtr(gpointer data); + bool HasRequested() const; + + private: + std::string port_name_; + std::string port_path_; + std::shared_ptr main_port_; + std::shared_ptr delegate_port_; + IEventListener* listener_ = nullptr; + std::string target_appid_; + std::string real_appid_; + int fds_[2]; + std::unique_ptr main_client_; + std::unique_ptr delegate_client_; + gpointer conn_timer_data_ = nullptr; + gpointer idler_data_ = nullptr; + mutable std::recursive_mutex mutex_; + std::unique_ptr file_monitor_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PROXY_INTERNAL_HH_ diff --git a/src/rpc-port/request-internal.cc b/src/rpc-port/request-internal.cc new file mode 100644 index 0000000..c293c29 --- /dev/null +++ b/src/rpc-port/request-internal.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 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 "request-internal.hh" + +#include + +namespace rpc_port { +namespace internal { + +Request::Request(std::string instance, std::string port_type) + : instance_(std::move(instance)), + port_type_(std::move(port_type)) { +} + +void Request::SetPortType(std::string port_type) { + port_type_ = std::move(port_type); +} + +const std::string& Request::GetInstance() { + return instance_; +} + +const std::string& Request::GetPortType() { + return port_type_; +} + +void Request::WriteToParcel(tizen_base::Parcel* parcel) const { + parcel->WriteString(instance_); + parcel->WriteString(port_type_); +} + +void Request::ReadFromParcel(tizen_base::Parcel* parcel) { + instance_ = parcel->ReadString(); + port_type_ = parcel->ReadString(); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/request-internal.hh b/src/rpc-port/request-internal.hh new file mode 100644 index 0000000..3aa9b05 --- /dev/null +++ b/src/rpc-port/request-internal.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef REQUEST_INTERNAL_HH_ +#define REQUEST_INTERNAL_HH_ + +#include +#include + +#include + +namespace rpc_port { +namespace internal { + +class Request : public tizen_base::Parcelable { + public: + Request(std::string instance, std::string port_type); + Request() = default; + ~Request() = default; + + void SetPortType(std::string port_type); + const std::string& GetInstance(); + const std::string& GetPortType(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + private: + std::string instance_; + std::string port_type_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // REQUEST_INTERNAL_HH_ diff --git a/src/rpc-port/response-internal.cc b/src/rpc-port/response-internal.cc new file mode 100644 index 0000000..9d32604 --- /dev/null +++ b/src/rpc-port/response-internal.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 "response-internal.hh" + +namespace rpc_port { +namespace internal { + +Response::Response(int result) : result_(result) { +} + +Response::Response() : result_(0) { +} + +int Response::GetResult() { + return result_; +} + +void Response::WriteToParcel(tizen_base::Parcel* parcel) const { + parcel->WriteInt32(result_); +} + +void Response::ReadFromParcel(tizen_base::Parcel* parcel) { + parcel->ReadInt32(&result_); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/response-internal.hh b/src/rpc-port/response-internal.hh new file mode 100644 index 0000000..2c12ab2 --- /dev/null +++ b/src/rpc-port/response-internal.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef RESPONSE_INTERNAL_HH_ +#define RESPONSE_INTERNAL_HH_ + +#include +#include + +namespace rpc_port { +namespace internal { + +class Response : public tizen_base::Parcelable { + public: + explicit Response(int result); + Response(); + ~Response() = default; + + int GetResult(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + private: + int result_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // RESPONSE_INTERNAL_HH_ diff --git a/src/rpc-port/rpc-port-internal.cc b/src/rpc-port/rpc-port-internal.cc new file mode 100644 index 0000000..ba78616 --- /dev/null +++ b/src/rpc-port/rpc-port-internal.cc @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include + +#include + +#include "include/rpc-port-internal.h" +#include "include/rpc-port.h" +#include "peer-cred-internal.hh" +#include "port-internal.hh" + +#undef RPC_API +#define RPC_API extern "C" __attribute__((visibility("default"))) + +namespace { +using namespace rpc_port::internal; + +constexpr uid_t kRegularUidMin = 5000; +std::atomic __target_uid { getuid() }; + +} // namespace + +RPC_API void rpc_port_set_target_uid(uid_t target_uid) { + __target_uid.exchange(target_uid); + set_last_result(RPC_PORT_ERROR_NONE); +} + +RPC_API uid_t rpc_port_get_target_uid(void) { + if (__target_uid < kRegularUidMin) + __target_uid.exchange(tzplatform_getuid(TZ_SYS_DEFAULT_USER)); + + return __target_uid; +} + +RPC_API int rpc_port_register_proc_info(const char* proc_name, bundle* extra) { + if (proc_name == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + int ret = aul_proc_register(proc_name, extra); + if (ret != AUL_R_OK) + return RPC_PORT_ERROR_IO_ERROR; + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_deregister_proc_info(void) { + int ret = aul_proc_deregister(); + if (ret != AUL_R_OK) + return RPC_PORT_ERROR_IO_ERROR; + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_get_peer_info(rpc_port_h h, pid_t* pid, uid_t* uid) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + std::shared_ptr cred(PeerCred::Get(port->GetFd())); + if (cred.get() == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + + if (pid) + *pid = cred->GetPid(); + + if (uid) + *uid = cred->GetUid(); + + return RPC_PORT_ERROR_NONE; +} + diff --git a/src/rpc-port/rpc-port-parcel.cc b/src/rpc-port/rpc-port-parcel.cc new file mode 100644 index 0000000..e78b6da --- /dev/null +++ b/src/rpc-port/rpc-port-parcel.cc @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2018 - 2021 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 "include/rpc-port-parcel.h" + +#include +#include +#include + +#include + +#include "log-private.hh" +#include "parcel-internal.hh" +#include "port-internal.hh" + +#define MAX_PARCEL_SIZE (1024 * 1024 * 10) + +#undef RPC_API +#define RPC_API extern "C" __attribute__((visibility("default"))) + +using namespace rpc_port; + +RPC_API int rpc_port_parcel_create(rpc_port_parcel_h* h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = new (std::nothrow) internal::Parcel(); + if (parcel == nullptr) + return RPC_PORT_ERROR_OUT_OF_MEMORY; + + *h = static_cast(parcel); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_create_from_port(rpc_port_parcel_h* h, + rpc_port_h port) { + int len; + unsigned char* buf; + + if (h == nullptr || port == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + internal::Port* pt = static_cast(port); + { + std::lock_guard lock(pt->GetMutex()); + int ret = rpc_port_read(port, &len, 4); + if (ret != 0) + return ret; + + if (len <= 0 || len > MAX_PARCEL_SIZE) + return RPC_PORT_ERROR_IO_ERROR; + + buf = static_cast(malloc(len)); + if (buf == nullptr) { + _E("Out of memory"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + } + + ret = rpc_port_read(port, buf, len); + if (ret != 0) { + free(buf); // LCOV_EXCL_LINE + return ret; // LCOV_EXCL_LINE + } + } + + auto* parcel = new (std::nothrow) internal::Parcel(); + if (parcel == nullptr) { + // LCOV_EXCL_START + _E("Out of memory"); + free(buf); + return RPC_PORT_ERROR_IO_ERROR; + // LCOV_EXCL_STOP + } + + tizen_base::Parcel raw_parcel(buf, len, false); + raw_parcel.ReadParcelable(parcel); + *h = static_cast(parcel); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_send(rpc_port_parcel_h h, rpc_port_h port) { + if (h == nullptr || port == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + tizen_base::Parcel raw_parcel; + raw_parcel.WriteParcelable(*parcel); + void* raw = reinterpret_cast(raw_parcel.GetData()); + uint32_t len = static_cast(raw_parcel.GetDataSize()); + if (len <= 0) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + internal::Port* pt = static_cast(port); + { + std::lock_guard lock(pt->GetMutex()); + int ret = rpc_port_write(port, &len, sizeof(len)); + if (ret != 0) + return ret; + + ret = rpc_port_write(port, raw, len); + if (ret != 0) + return ret; + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_destroy(rpc_port_parcel_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + delete parcel; + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_byte(rpc_port_parcel_h h, char b) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_byte(parcel->GetHandle(), b); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_int16(rpc_port_parcel_h h, short i) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_int16(parcel->GetHandle(), i); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_int32(rpc_port_parcel_h h, int i) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_int32(parcel->GetHandle(), i); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_int64(rpc_port_parcel_h h, long long i) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_int64(parcel->GetHandle(), i); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_float(rpc_port_parcel_h h, float f) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_float(parcel->GetHandle(), f); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_double(rpc_port_parcel_h h, double d) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_double(parcel->GetHandle(), d); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_string(rpc_port_parcel_h h, const char* str) { + if (h == nullptr || str == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_string(parcel->GetHandle(), str); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_bool(rpc_port_parcel_h h, bool b) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_bool(parcel->GetHandle(), b); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_bundle(rpc_port_parcel_h h, bundle* b) { + if (h == nullptr || b == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + bundle_raw* raw = nullptr; + int len = 0; + bundle_encode(b, &raw, &len); + auto ptr = std::unique_ptr(raw, std::free); + + auto* parcel = static_cast(h); + parcel_write_string(parcel->GetHandle(), reinterpret_cast(raw)); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write_array_count(rpc_port_parcel_h h, int count) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_write_int32(parcel->GetHandle(), count); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_write(rpc_port_parcel_h h, + rpc_port_parcelable_t* parcelable, void* data) { + if (parcelable == nullptr || parcelable->to == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + parcelable->to(h, data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_byte(rpc_port_parcel_h h, char* b) { + if (h == nullptr || b == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_byte(parcel->GetHandle(), b); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_byte() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_int16(rpc_port_parcel_h h, short* i) { + if (h == nullptr || i == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_int16(parcel->GetHandle(), i); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_int16() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_int32(rpc_port_parcel_h h, int* i) { + if (h == nullptr || i == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_int32(parcel->GetHandle(), i); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_int32() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_int64(rpc_port_parcel_h h, long long* i) { + if (h == nullptr || i == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int64_t val = 0; + int ret = parcel_read_int64(parcel->GetHandle(), &val); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_int64() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + *i = static_cast(val); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_float(rpc_port_parcel_h h, float* f) { + if (h == nullptr || f == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_float(parcel->GetHandle(), f); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_float() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_double(rpc_port_parcel_h h, double* d) { + if (h == nullptr || d == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_double(parcel->GetHandle(), d); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read_double() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_string(rpc_port_parcel_h h, char** str) { + if (h == nullptr || str == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_string(parcel->GetHandle(), str); + if (ret != PARCEL_ERROR_NONE) { + _E("parcel_read_string() is failed. error(%d)", ret); // LCOV_EXCL_LINE + *str = strdup(""); // LCOV_EXCL_LINE + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_bool(rpc_port_parcel_h h, bool* b) { + if (h == nullptr || b == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_bool(parcel->GetHandle(), b); + if (ret != 0) + _E("parcel_read_bool() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_bundle(rpc_port_parcel_h h, bundle** b) { + if (h == nullptr || b == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + char* raw = nullptr; + int ret = parcel_read_string(parcel->GetHandle(), &raw); + if (ret != 0) { + _E("parcel_read_string() is failed. error(%d)", ret); // LCOV_EXCL_LINE + *b = bundle_create(); // LCOV_EXCL_LINE + } else { + *b = bundle_decode(reinterpret_cast(raw), strlen(raw)); + std::free(raw); + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read_array_count(rpc_port_parcel_h h, int* count) { + if (h == nullptr || count == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + int ret = parcel_read_int32(parcel->GetHandle(), count); + if (ret != 0) + _E("parcel_read_int32() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_read(rpc_port_parcel_h h, + rpc_port_parcelable_t* parcelable, void* data) { + if (parcelable == nullptr || parcelable->from == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + parcelable->from(h, data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_burst_read(rpc_port_parcel_h h, unsigned char *buf, + unsigned int size) { + if (h == nullptr || buf == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + uint32_t valid_size = size & UINT32_MAX; + int ret = parcel_burst_read(parcel->GetHandle(), static_cast(buf), + valid_size); + if (ret != PARCEL_ERROR_NONE) + _E("parcel_read() is failed. error(%d)", ret); // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_burst_write(rpc_port_parcel_h h, + const unsigned char *buf, unsigned int size) { + if (h == nullptr || buf == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + uint32_t valid_size = size & UINT32_MAX; + parcel_burst_write(parcel->GetHandle(), static_cast(buf), + valid_size); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_reset_reader(rpc_port_parcel_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + parcel_reset_reader(parcel->GetHandle()); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_to_array(rpc_port_parcel_h h, void** array, + unsigned int* size) { + if (h == nullptr || !array || !size) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + tizen_base::Parcel raw_parcel; + raw_parcel.WriteParcelable(*parcel); + void* raw = raw_parcel.GetData(); + size_t raw_size = raw_parcel.GetDataSize(); + if (raw_size == 0) { + _E("raw_size is zero"); + return RPC_PORT_ERROR_IO_ERROR; + } + + void* array_ptr = malloc(raw_size); + if (array_ptr == nullptr) + return RPC_PORT_ERROR_OUT_OF_MEMORY; + + memcpy(array_ptr, raw, raw_size); + *array = array_ptr; + *size = static_cast(raw_size); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_from_array(rpc_port_parcel_h h, const void* array, + unsigned int size) { + if (h == nullptr || array == nullptr || size == 0) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + uint32_t valid_size = size & UINT32_MAX; + tizen_base::Parcel raw_parcel(array, valid_size); + raw_parcel.ReadParcelable(parcel); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_get_header(rpc_port_parcel_h h, + rpc_port_parcel_header_h* header) { + if (h == nullptr || header == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + auto* parcel_header = parcel->GetParcelHeader(); + if (parcel_header == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + *header = reinterpret_cast( + const_cast(parcel_header)); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_header_set_tag(rpc_port_parcel_header_h header, + const char* tag) { + if (header == nullptr || tag == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel_header = static_cast(header); + parcel_header->SetTag(tag); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_header_get_tag(rpc_port_parcel_header_h header, + char** tag) { + if (header == nullptr || tag == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel_header = static_cast(header); + const std::string& raw_tag = parcel_header->GetTag(); + + *tag = strdup(raw_tag.c_str()); + if (*tag == nullptr) + return RPC_PORT_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_header_set_seq_num(rpc_port_parcel_header_h header, + int seq_num) { + if (header == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel_header = static_cast(header); + parcel_header->SetSeqNum(seq_num); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_header_get_seq_num(rpc_port_parcel_header_h header, + int* seq_num) { + if (header == nullptr || seq_num == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel_header = static_cast(header); + *seq_num = parcel_header->GetSeqNum(); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_header_get_timestamp( + rpc_port_parcel_header_h header, struct timespec* timestamp) { + if (header == nullptr || timestamp == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel_header = static_cast(header); + *timestamp = parcel_header->GetTimeStamp(); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_get_raw(rpc_port_parcel_h h, void** raw, + unsigned int* size) { + if (h == nullptr || raw == nullptr || size == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = static_cast(h); + auto* raw_parcel = new (std::nothrow) tizen_base::Parcel(); + if (raw_parcel != nullptr) { + raw_parcel->WriteParcelable(*parcel); + parcel->SetRawParcel(raw_parcel); + *raw = raw_parcel->GetData(); + *size = static_cast(raw_parcel->GetDataSize()); + } else { + // LCOV_EXCL_START + _E("Out of memory"); + *raw = nullptr; + *size = 0; + // LCOV_EXCL_STOP + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_create_from_raw(rpc_port_parcel_h* h, + const void* raw, unsigned int size) { + if (h == nullptr || raw == nullptr || size == 0) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + rpc_port_parcel_h parcel; + int ret = rpc_port_parcel_create(&parcel); + if (ret != RPC_PORT_ERROR_NONE) + return ret; + + ret = rpc_port_parcel_from_array(parcel, raw, size); + if (ret != RPC_PORT_ERROR_NONE) { + rpc_port_parcel_destroy(parcel); // LCOV_EXCL_LINE + return ret; // LCOV_EXCL_LINE + } + + *h = parcel; + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_parcel_create_without_header(rpc_port_parcel_h* h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto* parcel = new (std::nothrow) internal::Parcel(true); + if (parcel == nullptr) + return RPC_PORT_ERROR_OUT_OF_MEMORY; + + *h = static_cast(parcel); + return RPC_PORT_ERROR_NONE; +} diff --git a/src/rpc-port/rpc-port.cc b/src/rpc-port/rpc-port.cc new file mode 100644 index 0000000..023a9ab --- /dev/null +++ b/src/rpc-port/rpc-port.cc @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2017 - 2021 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 "include/rpc-port.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "include/rpc-port-internal.h" +#include "log-private.hh" +#include "port-internal.hh" +#include "proxy-internal.hh" +#include "stub-internal.hh" + +#undef RPC_API +#define RPC_API extern "C" __attribute__((visibility("default"))) + +namespace { +using namespace rpc_port::internal; + +template +class Event { + public: + Event(T cb, void* user_data) + : cb_(cb), user_data_(user_data) {} + + T cb_; + void* user_data_; +}; + +class ProxyExt : public Proxy, public Proxy::IEventListener { + public: + ProxyExt() : Proxy(), destroying_(false) {} + virtual ~ProxyExt() = default; + + void AddConnectedEventListener(rpc_port_proxy_connected_event_cb cb, + void* user_data) { + connected_events_.emplace_back( + new Event(cb, user_data)); + } + + void AddDisconnectedEventListener(rpc_port_proxy_disconnected_event_cb cb, + void* user_data) { + disconnected_events_.emplace_back( + new Event(cb, user_data)); + } + + void AddRejectedEventListener(rpc_port_proxy_rejected_event_cb cb, + void* user_data) { + rejected_events_.emplace_back( + new Event(cb, user_data)); + } + + void AddReceivedEventListener(rpc_port_proxy_received_event_cb cb, + void* user_data) { + received_events_.emplace_back( + new Event(cb, user_data)); + } + + void OnConnected(const std::string& endpoint, Port* port) override { + if (IsDestroying()) + return; + + for (auto& ev : connected_events_) { + ev->cb_(endpoint.c_str(), GetPortName().c_str(), port, + ev->user_data_); + } + } + + void OnDisconnected(const std::string& endpoint) override { + if (IsDestroying()) + return; + + for (auto& ev : disconnected_events_) { + ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); + } + } + + void OnRejected(const std::string& endpoint, int err_code) override { + if (IsDestroying()) + return; + + for (auto& ev : rejected_events_) { + set_last_result(err_code); + ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); + } + } + + void OnReceived(const std::string& endpoint) override { + if (IsDestroying()) + return; + + for (auto& ev : received_events_) { + ev->cb_(endpoint.c_str(), GetPortName().c_str(), ev->user_data_); + } + } + + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + void SetDestroying(bool destroying) { + destroying_ = destroying; + } + + bool IsDestroying() { + return destroying_; + } + + private: + std::atomic destroying_; + std::list>> + connected_events_; + std::list>> + disconnected_events_; + std::list>> + rejected_events_; + std::list>> + received_events_; + mutable std::recursive_mutex mutex_; +}; + +class StubExt : public Stub, public Stub::IEventListener { + public: + explicit StubExt(const std::string& port) : Stub(port), destroying_(false) {} + virtual ~StubExt() = default; + + void AddConnectedEventListener(rpc_port_stub_connected_event_cb cb, + void* user_data) { + connected_events_.emplace_back( + new Event(cb, user_data)); + } + + void AddDisconnectedEventListener(rpc_port_stub_disconnected_event_cb cb, + void* user_data) { + disconnected_events_.emplace_back( + new Event(cb, user_data)); + } + + void AddReceivedEventListener(rpc_port_stub_received_event_cb cb, + void* user_data) { + received_events_.emplace_back( + new Event(cb, user_data)); + } + + void OnConnected(const std::string& sender, + const std::string& instance) override { + if (IsDestroying()) + return; + + for (auto& ev : connected_events_) { + ev->cb_(sender.c_str(), instance.c_str(), ev->user_data_); + } + } + + void OnDisconnected(const std::string& sender, + const std::string& instance) override { + if (IsDestroying()) + return; + + for (auto& ev : disconnected_events_) { + ev->cb_(sender.c_str(), instance.c_str(), ev->user_data_); + } + } + + int OnReceived(const std::string& sender, + const std::string& instance, Port* port) override { + if (IsDestroying()) + return -1; + + for (auto& ev : received_events_) { + int ret = ev->cb_(sender.c_str(), instance.c_str(), port, + ev->user_data_); + if (ret != 0) + return -1; + } + + return 0; + } + + void SetDestroying(bool destroying) { + destroying_ = destroying; + } + + bool IsDestroying() { + return destroying_; + } + + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + private: + std::atomic destroying_; + std::list>> + connected_events_; + std::list>> + disconnected_events_; + std::list>> + received_events_; + mutable std::recursive_mutex mutex_; +}; + +} // namespace + +RPC_API int rpc_port_read(rpc_port_h h, void* buf, unsigned int size) { + if (h == nullptr || buf == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + uint32_t seq = 0; + if (DebugPort::IsConnected()) { + int ret = port->Read(reinterpret_cast(&seq), sizeof(seq)); + if (ret < 0) { + _E("IO Error"); + return ret; + } + } + + int ret = port->Read(buf, size); + if (ret < 0) { + _E("IO Error"); + return ret; + } + + if (DebugPort::IsConnected()) + DebugPort::Send(port->GetFd(), true, seq, buf, size); + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_write(rpc_port_h h, const void* buf, unsigned int size) { + if (h == nullptr || buf == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + uint32_t seq = port->GetSeq(); + if (DebugPort::IsConnected()) { + int ret = port->Write(reinterpret_cast(&seq), sizeof(seq)); + if (ret < 0) + return ret; + } + + int ret = port->Write(buf, size); + if (ret < 0) + return ret; + + if (DebugPort::IsConnected()) + DebugPort::Send(port->GetFd(), false, seq, buf, size); + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = new (std::nothrow) std::shared_ptr<::ProxyExt>( + new (std::nothrow) ::ProxyExt()); + if (p == nullptr) { + _E("Out of memory"); // LCOV_EXCL_LINE + } else if (p->get() == nullptr) { + // LCOV_EXCL_START + _E("Out of memory"); + delete p; + p = nullptr; + // LCOV_EXCL_STOP + } else { + _W("rpc_port_proxy_create(%p)", p->get()); + } + + *h = p; + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + if (proxy->IsDestroying()) { + _E("already destroyed. handle(%p)", proxy); // LCOV_EXCL_LINE + abort(); // LCOV_EXCL_LINE + } + + _W("rpc_port_proxy_destroy(%p)", proxy); + proxy->SetDestroying(true); + proxy->DisconnectPort(); + + g_idle_add_full(G_PRIORITY_HIGH, + [](gpointer data) -> gboolean { + auto p = static_cast*>(data); + _W("rpc_port_proxy_destroy(%p)", p->get()); + delete p; + return G_SOURCE_REMOVE; + }, h, nullptr); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, + const char* port) { + if (h == nullptr || appid == nullptr || port == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); + std::lock_guard lock(proxy->GetMutex()); + return proxy->Connect(appid, port, proxy); +} + +// LCOV_EXCL_START +RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, + const char* port) { + if (h == nullptr || appid == nullptr || port == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); + std::lock_guard lock(proxy->GetMutex()); + return proxy->ConnectSync(appid, port, proxy); +} +// LCOV_EXCL_STOP + +RPC_API int rpc_port_proxy_add_connected_event_cb(rpc_port_proxy_h h, + rpc_port_proxy_connected_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddConnectedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_add_disconnected_event_cb(rpc_port_proxy_h h, + rpc_port_proxy_disconnected_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddDisconnectedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_add_rejected_event_cb(rpc_port_proxy_h h, + rpc_port_proxy_rejected_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddRejectedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_add_received_event_cb(rpc_port_proxy_h h, + rpc_port_proxy_received_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddReceivedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_proxy_get_port(rpc_port_proxy_h h, + rpc_port_port_type_e type, rpc_port_h* port) { + if (h == nullptr || port == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + rpc_port_h ret_port; + + switch (type) { + case RPC_PORT_PORT_MAIN: + ret_port = static_cast(proxy->GetPort().get()); + if (ret_port == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + *port = ret_port; + break; + case RPC_PORT_PORT_CALLBACK: + ret_port = static_cast(proxy->GetDelegatePort().get()); + if (ret_port == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + *port = ret_port; + break; + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { + if (h == nullptr || port_name == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = new ::StubExt(port_name); + *h = p; + _W("rpc_port_stub_create(%p, %s)", p, port_name); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_destroy(rpc_port_stub_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + _W("rpc_port_stub_destroy(%p)", h); + auto p = static_cast<::StubExt*>(h); + if (p->IsDestroying()) { + _E("already destroyed. handle(%p)", h); // LCOV_EXCL_LINE + abort(); // LCOV_EXCL_LINE + } + + p->SetDestroying(true); + aul_rpc_port_usr_destroy(p->GetPortName().c_str(), rpc_port_get_target_uid()); + p->Ignore(); + g_idle_add_full(G_PRIORITY_HIGH, + [](gpointer data) -> gboolean { + auto p = static_cast<::StubExt*>(data); + _W("rpc_port_stub_destroy(%p)", p); + delete p; + return G_SOURCE_REMOVE; + }, h, nullptr); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_listen(rpc_port_stub_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + _W("rpc_port_stub_listen(%p)", h); + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + int fd = p->CreatePort(); + if (fd < 0) + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE + + return p->Listen(p, fd); +} + +RPC_API int rpc_port_stub_add_privilege(rpc_port_stub_h h, + const char* privilege) { + if (h == nullptr || privilege == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + p->AddPrivilege(privilege); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_set_trusted(rpc_port_stub_h h, + const bool trusted) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + p->SetTrusted(trusted); + return RPC_PORT_ERROR_NONE; +} + + +RPC_API int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h, + rpc_port_stub_connected_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + p->AddConnectedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_add_disconnected_event_cb(rpc_port_stub_h h, + rpc_port_stub_disconnected_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + p->AddDisconnectedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_add_received_event_cb(rpc_port_stub_h h, + rpc_port_stub_received_event_cb cb, void* user_data) { + if (h == nullptr || cb == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + + p->AddReceivedEventListener(cb, user_data); + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_stub_get_port(rpc_port_stub_h h, + rpc_port_port_type_e type, const char* instance, rpc_port_h* port) { + if (h == nullptr || port == nullptr || instance == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto p = static_cast<::StubExt*>(h); + std::lock_guard lock(p->GetMutex()); + rpc_port_h ret_port; + + switch (type) { + case RPC_PORT_PORT_MAIN: + ret_port = static_cast(p->FindPort(instance).get()); + if (ret_port == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + *port = ret_port; + break; + case RPC_PORT_PORT_CALLBACK: + ret_port = static_cast(p->FindDelegatePort(instance).get()); + if (ret_port == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + *port = ret_port; + break; + } + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_set_private_sharing_array(rpc_port_h h, + const char* paths[], unsigned int size) { + if (h == nullptr || paths == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + + return port->SetPrivateSharing(paths, size); +} + +RPC_API int rpc_port_set_private_sharing(rpc_port_h h, const char* path) { + if (h == nullptr || path == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + + return port->SetPrivateSharing(path); +} + +RPC_API int rpc_port_unset_private_sharing(rpc_port_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + + return port->UnsetPrivateSharing(); +} + +RPC_API int rpc_port_disconnect(rpc_port_h h) { + if (h == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + port->Disconnect(); + + return RPC_PORT_ERROR_NONE; +} diff --git a/src/rpc-port/server-socket-internal.cc b/src/rpc-port/server-socket-internal.cc new file mode 100644 index 0000000..3aca86b --- /dev/null +++ b/src/rpc-port/server-socket-internal.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 "server-socket-internal.hh" + +#include +#include +#include +#include +#include +#include +#include + +#include "exception-internal.hh" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +ServerSocket::ServerSocket() { + fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd_ < 0) { + fd_ = -errno; + _E("socket() is failed. errno(%d)", errno); + THROW(fd_); + } +} + +ServerSocket::ServerSocket(int fd) : fd_(fd) { + SetCloseOnExec(); +} + +ServerSocket::~ServerSocket() { + if (!IsClosed()) + Close(); +} + +bool ServerSocket::IsClosed() { + return fd_ < 0 ? true : false; +} + +ClientSocket* ServerSocket::Accept() { + struct sockaddr_un addr = { 0, }; + socklen_t len = static_cast(sizeof(struct sockaddr_un)); + auto* addr_ptr = reinterpret_cast(&addr); + int client_fd = accept(GetFd(), addr_ptr, &len); + if (client_fd == -1) { + _E("accept() is failed. errno(%d)", errno); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE + } + + return new (std::nothrow) ClientSocket(client_fd); +} + +int ServerSocket::GetFd() const { + return fd_; +} + +void ServerSocket::Bind(const std::string& bindpoint) { + struct sockaddr_un sockaddr = { 0, }; + sockaddr.sun_family = AF_UNIX; + snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", + bindpoint.c_str()); + struct sockaddr* sockaddr_ptr = reinterpret_cast(&sockaddr); + socklen_t len = static_cast(sizeof(sockaddr)); + + unlink(bindpoint.c_str()); + int ret = bind(GetFd(), sockaddr_ptr, len); + if (ret < 0) { + ret = -errno; + _E("bind() is failed. errno(%d)", errno); + THROW(ret); + } +} + +// LCOV_EXCL_START +int ServerSocket::Listen(int backlog) { + int ret = listen(GetFd(), backlog); + if (ret < 0) { + _E("listen() is failed. errno(%d)", errno); + return -1; + } + + return 0; +} + +void ServerSocket::SetCloseOnExec() { + int flags = fcntl(fd_, F_GETFL, 0); + fcntl(fd_, F_SETFL, flags | FD_CLOEXEC); + _I("Close on exec. fd(%d)", fd_); +} +// LCOV_EXCL_STOP + +void ServerSocket::Close() { + if (fd_ > -1) { + close(fd_); + fd_ = -1; + } +} + +int ServerSocket::RemoveFd() { + int fd = fd_; + fd_ = -1; + return fd; +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/server-socket-internal.hh b/src/rpc-port/server-socket-internal.hh new file mode 100644 index 0000000..ee96155 --- /dev/null +++ b/src/rpc-port/server-socket-internal.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef SERVER_SOCKET_INTERNAL_HH_ +#define SERVER_SOCKET_INTERNAL_HH_ + +#include + +#include "client-socket-internal.hh" + +namespace rpc_port { +namespace internal { + +class ServerSocket { + public: + ServerSocket(); + explicit ServerSocket(int fd); + virtual ~ServerSocket(); + + bool IsClosed(); + ClientSocket* Accept(); + int GetFd() const; + void Bind(const std::string& endpoint); + int Listen(int backlog); + void Close(); + void SetCloseOnExec(); + int RemoveFd(); + + private: + int fd_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // SERVER_SOCKET_INTERNAL_HH_ diff --git a/src/rpc-port/stub-internal.cc b/src/rpc-port/stub-internal.cc new file mode 100644 index 0000000..eccdd29 --- /dev/null +++ b/src/rpc-port/stub-internal.cc @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2017 - 2021 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 "stub-internal.hh" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "aul-internal.hh" +#include "debug-port-internal.hh" +#include "exception-internal.hh" +#include "include/rpc-port.h" +#include "log-private.hh" +#include "peer-cred-internal.hh" +#include "request-internal.hh" +#include "response-internal.hh" + +namespace rpc_port { +namespace internal { +namespace { + +constexpr const char kPortTypeMain[] = "main"; +constexpr const char kPortTypeDelegate[] = "delegate"; +constexpr uid_t kRegularUidMin = 5000; + +int ReceiveRequest(ClientSocket* client, Request** request) { + size_t size = 0; + int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + std::vector buf(size); + ret = client->Receive(buf.data(), size); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + tizen_base::Parcel parcel(buf.data(), buf.size()); + *request = new (std::nothrow) Request(); + if (*request == nullptr) { + _E("Out of memory"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + parcel.ReadParcelable(*request); + return 0; +} + +int SendResponse(ClientSocket* client, const Response& response) { + tizen_base::Parcel parcel; + parcel.WriteParcelable(const_cast(response)); + size_t size = parcel.GetDataSize(); + int ret = client->Send(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + ret = client->Send(parcel.GetData(), size); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +} // namespace + +std::unordered_set Stub::freed_stubs_; + +Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) { + _D("Stub::Stub()"); + freed_stubs_.erase(this); +} + +Stub::~Stub() { + std::lock_guard lock(GetMutex()); + _D("Stub::~Stub"); + for (auto& p : ports_) { + if (!p->IsDelegate()) + DebugPort::RemoveSession(p->GetFd()); + } + + listener_ = nullptr; + server_.reset(); + if (!port_path_.empty()) { + _W("Delete port path=%s", port_path_.c_str()); + unlink(port_path_.c_str()); + } + + freed_stubs_.insert(this); +} + +int Stub::Listen(IEventListener* ev, int fd) { + if (ev == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + std::lock_guard lock(GetMutex()); + if (listener_ != nullptr) { + _E("Already listening!"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE + } + + listener_ = ev; + server_.reset(new Server(fd, this)); + return server_->Listen(); +} + +void Stub::Ignore() { + std::lock_guard lock(GetMutex()); + listener_ = nullptr; +} + +void Stub::AddPrivilege(const std::string& privilege) { + std::lock_guard lock(GetMutex()); + access_controller_->AddPrivilege(privilege); +} + +void Stub::SetTrusted(const bool trusted) { + std::lock_guard lock(GetMutex()); + access_controller_->SetTrusted(trusted); +} + +// LCOV_EXCL_START +std::shared_ptr Stub::FindPort(const std::string& instance) const { + std::lock_guard lock(GetMutex()); + for (auto& p : ports_) { + if (p->GetInstance() == instance && !p->IsDelegate()) { + return p; + } + } + + return {}; +} +// LCOV_EXCL_STOP + +std::shared_ptr Stub::FindDelegatePort( + const std::string& instance) const { + std::lock_guard lock(GetMutex()); + for (auto& p : ports_) { + if (p->GetInstance() == instance && p->IsDelegate()) { + return p; + } + } + + return {}; +} + +const std::string& Stub::GetPortName() const { + return port_name_; +} + +void Stub::RemoveAcceptedPorts(std::string instance) { + std::lock_guard lock(GetMutex()); + auto iter = ports_.begin(); + while (iter != ports_.end()) { + if ((*iter)->GetInstance().compare(instance) == 0) { + LOGI("Close: fd(%d)", (*iter)->GetFd()); + DebugPort::RemoveSession((*iter)->GetFd()); + iter = ports_.erase(iter); + } else { + iter++; + } + } +} + +int Stub::CreatePort() { + if (getenv("AUL_APPID") == nullptr) { + std::string name = Aul::GetName(getpid()); + if (!name.empty()) { + port_path_ = Aul::GetPortPath(name, GetPortName(), getuid()); + int fd = GetFdFromSystemd(); + if (fd > -1) return fd; + + fd = CreateServerSocket(); + if (fd > -1) return fd; + } + } + + int fd = -1; + int ret = aul_rpc_port_usr_create(GetPortName().c_str(), getuid(), &fd); + if (ret != AUL_R_OK) { + // LCOV_EXCL_START + _E("aul_rpc_port_usr_create() is failed. error(%d)", ret); + return RPC_PORT_ERROR_IO_ERROR; + // LCOV_EXCL_STOP + } + + return fd; +} + +int Stub::GetFdFromSystemd() { + int fds = sd_listen_fds(0); + for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fds; ++fd) { + if (sd_is_socket_unix(fd, SOCK_STREAM, 1, port_path_.c_str(), 0) > 0) + return fd; + } + + _E("There is no socket stream"); + return -1; +} + +int Stub::CreateServerSocket() { + try { + ServerSocket socket; + socket.Bind(port_path_); + socket.Listen(128); + return socket.RemoveFd(); + } catch (const Exception& e) { + _E("Exception occurs. error(%s)", e.what()); + return -1; + } +} + +gboolean Stub::AcceptedPort::OnDataReceived(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + auto* listener = stub->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + int fd = g_io_channel_unix_get_fd(channel); + for (auto& p : stub->ports_) { + if (p->GetFd() == fd && !p->IsDelegate()) { + char buffer[4]; + if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { + _W("Socket was disconnected from proxy. fd(%d)", fd); + listener->OnDisconnected(p->GetId(), p->GetInstance()); + stub->RemoveAcceptedPorts(p->GetInstance()); + Aul::NotifyRpcFinished(); + return G_SOURCE_CONTINUE; + } + + int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(), + p.get()); + if (ret != 0) { + _W("Invalid protocol"); + listener->OnDisconnected(p->GetId(), p->GetInstance()); + stub->RemoveAcceptedPorts(p->GetInstance()); + Aul::NotifyRpcFinished(); + return G_SOURCE_CONTINUE; + } + + break; + } + } + + return G_SOURCE_CONTINUE; +} + +gboolean Stub::AcceptedPort::OnSocketDisconnected(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + auto* listener = stub->listener_; + if (listener == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + int fd = g_io_channel_unix_get_fd(channel); + _W("Socket was disconnected. fd(%d)", fd); + for (auto& p : stub->ports_) { + if (p->GetFd() == fd) { + listener->OnDisconnected(p->GetId(), p->GetInstance()); + stub->RemoveAcceptedPorts(p->GetInstance()); + Aul::NotifyRpcFinished(); + break; + } + } + + return G_SOURCE_REMOVE; +} + +void Stub::AddAcceptedPort(const std::string& sender_appid, + const std::string& instance, const std::string& port_type, int fd) { + std::lock_guard lock(GetMutex()); + if (port_type == kPortTypeMain) { + auto* main_port = new AcceptedPort(this, false, fd, sender_appid, + instance, true); + ports_.emplace_back(main_port); + return; + } + + auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid, + instance, false); + ports_.emplace_back(delegate_port); + + int main_fd = -1; + for (auto& p : ports_) { + if (p->GetId() == delegate_port->GetId() && + p->GetInstance() == delegate_port->GetInstance() && + p->GetFd() != delegate_port->GetFd()) { + main_fd = p->GetFd(); + break; + } + } + + _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)", + sender_appid.c_str(), instance.c_str(), main_fd, fd); + DebugPort::AddSession(port_name_, sender_appid, main_fd, fd); + listener_->OnConnected(sender_appid, instance); +} + +std::recursive_mutex& Stub::GetMutex() const { + return mutex_; +} + +Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, + std::string id, std::string inst, bool watch) + : Port(fd, std::move(id), std::move(inst)), parent_(parent), + is_delegate_(isDelegate) { + Watch(watch); +} + +// LCOV_EXCL_START +Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, + std::string id, bool watch) + : Port(fd, std::move(id)), parent_(parent), + is_delegate_(isDelegate) { + Watch(watch); +} +// LCOV_EXCL_STOP + +Stub::AcceptedPort::~AcceptedPort() { + if (disconn_source_ > 0) + g_source_remove(disconn_source_); + + if (source_ > 0) + g_source_remove(source_); + + if (channel_ != nullptr) + g_io_channel_unref(channel_); +} + +int Stub::AcceptedPort::Watch(bool receive) { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + disconn_source_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + OnSocketDisconnected, parent_); + if (disconn_source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + if (!receive) + return 0; + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + OnDataReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +Stub::Server::Server(int fd, Stub* parent) + : ServerSocket(fd), + parent_(parent) { +} + +Stub::Server::~Server() { + if (channel_) + g_io_channel_unref(channel_); + + if (source_ > 0) + g_source_remove(source_); +} + +int Stub::Server::Listen() { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + OnRequestReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE + } + + return 0; +} + +gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data) { + auto* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + if (stub->listener_ == nullptr) { + _E("Invalid context"); // LCOV_EXCL_LINE + return G_SOURCE_REMOVE; // LCOV_EXCL_LINE + } + + std::shared_ptr client(stub->server_->Accept()); + if (client.get() == nullptr) { + _E("Out of memory"); // LCOV_EXCL_LINE + return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE + } + + Request* request = nullptr; + int ret = ReceiveRequest(client.get(), &request); + if (ret != 0) + return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE + + std::shared_ptr request_auto(request); + std::shared_ptr cred(PeerCred::Get(client->GetFd())); + if (cred.get() == nullptr) { + _E("Failed to create peer credentials"); // LCOV_EXCL_LINE + return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE + } + + std::string app_id = Aul::GetAppId(cred->GetPid()); + auto response_func = [=](int res) -> void { + if (freed_stubs_.find(stub) != freed_stubs_.end()) + return; // LCOV_EXCL_LINE + + Response response(res); + int ret = SendResponse(client.get(), response); + if (ret != 0) + return; // LCOV_EXCL_LINE + + if (res != 0) { + _E("Access denied. fd(%d), pid(%d)", + client->GetFd(), cred->GetPid()); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE + } + + client->SetNonblock(); + int client_fd = client->RemoveFd(); + stub->AddAcceptedPort(app_id, request_auto->GetInstance(), + request_auto->GetPortType(), client_fd); + }; + + int res; + if (cred->GetUid() >= kRegularUidMin) { + if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) { + _E("Reject request. %u:%u", cred->GetUid(), getuid()); // LCOV_EXCL_LINE + res = -1; // LCOV_EXCL_LINE + } else { + stub->access_controller_->CheckAsync(client->GetFd(), app_id, + response_func); + return G_SOURCE_CONTINUE; + } + } else { + _W("Bypass access control. pid(%d), uid(%u)", + cred->GetPid(), cred->GetUid()); + res = 0; + } + + response_func(res); + return G_SOURCE_CONTINUE; +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/rpc-port/stub-internal.hh b/src/rpc-port/stub-internal.hh new file mode 100644 index 0000000..b1ac248 --- /dev/null +++ b/src/rpc-port/stub-internal.hh @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef STUB_INTERNAL_HH_ +#define STUB_INTERNAL_HH_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ac-internal.hh" +#include "debug-port-internal.hh" +#include "port-internal.hh" +#include "server-socket-internal.hh" + +namespace rpc_port { +namespace internal { + +class Stub { + public: + class IEventListener { + public: + virtual void OnConnected(const std::string& sender, + const std::string& instance) = 0; + virtual void OnDisconnected(const std::string& sender, + const std::string& instance) = 0; + virtual int OnReceived(const std::string& sender, + const std::string& instance, Port* port) = 0; + }; + + explicit Stub(std::string port_name); + virtual ~Stub(); + + int Listen(IEventListener* ev, int fd); + void Ignore(); + void AddPrivilege(const std::string& privilege); + void SetTrusted(const bool trusted); + std::shared_ptr FindPort(const std::string& instance) const; + std::shared_ptr FindDelegatePort(const std::string& instance) const; + const std::string& GetPortName() const; + int CreatePort(); + + private: + class AcceptedPort : public Port { + public: + AcceptedPort(Stub* parent, bool isDelegate, int fd, std::string id, + std::string inst, bool receive); + AcceptedPort(Stub* parent, bool isDelegate, int fd, std::string id, + bool receive); + virtual ~AcceptedPort(); + bool IsDelegate() const { + return is_delegate_; + } + + private: + int Watch(bool receive); + static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + GIOChannel* channel_ = nullptr; + guint disconn_source_ = 0; + guint source_ = 0; + Stub* parent_; + bool is_delegate_ = false; + }; + + class Server : public ServerSocket { + public: + Server(int fd, Stub* parent); + virtual ~Server(); + + int Listen(); + + private: + static gboolean OnRequestReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + Stub* parent_; + GIOChannel* channel_ = nullptr; + guint source_ = 0; + }; + + void AddAcceptedPort(const std::string& sender_appid, + const std::string& instance, const std::string& port_type, int fd); + void RemoveAcceptedPorts(std::string instance); + std::recursive_mutex& GetMutex() const; + int GetFdFromSystemd(); + int CreateServerSocket(); + + private: + std::shared_ptr access_controller_ = + std::make_shared(); + std::string port_name_; + std::string port_path_; + std::list> ports_; + IEventListener* listener_ = nullptr; + std::unique_ptr server_; + mutable std::recursive_mutex mutex_; + static std::unordered_set freed_stubs_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // STUB_INTERNAL_HH_ diff --git a/src/server-socket-internal.cc b/src/server-socket-internal.cc deleted file mode 100644 index 3aca86b..0000000 --- a/src/server-socket-internal.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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 "server-socket-internal.hh" - -#include -#include -#include -#include -#include -#include -#include - -#include "exception-internal.hh" -#include "log-private.hh" - -namespace rpc_port { -namespace internal { - -ServerSocket::ServerSocket() { - fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (fd_ < 0) { - fd_ = -errno; - _E("socket() is failed. errno(%d)", errno); - THROW(fd_); - } -} - -ServerSocket::ServerSocket(int fd) : fd_(fd) { - SetCloseOnExec(); -} - -ServerSocket::~ServerSocket() { - if (!IsClosed()) - Close(); -} - -bool ServerSocket::IsClosed() { - return fd_ < 0 ? true : false; -} - -ClientSocket* ServerSocket::Accept() { - struct sockaddr_un addr = { 0, }; - socklen_t len = static_cast(sizeof(struct sockaddr_un)); - auto* addr_ptr = reinterpret_cast(&addr); - int client_fd = accept(GetFd(), addr_ptr, &len); - if (client_fd == -1) { - _E("accept() is failed. errno(%d)", errno); // LCOV_EXCL_LINE - return nullptr; // LCOV_EXCL_LINE - } - - return new (std::nothrow) ClientSocket(client_fd); -} - -int ServerSocket::GetFd() const { - return fd_; -} - -void ServerSocket::Bind(const std::string& bindpoint) { - struct sockaddr_un sockaddr = { 0, }; - sockaddr.sun_family = AF_UNIX; - snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", - bindpoint.c_str()); - struct sockaddr* sockaddr_ptr = reinterpret_cast(&sockaddr); - socklen_t len = static_cast(sizeof(sockaddr)); - - unlink(bindpoint.c_str()); - int ret = bind(GetFd(), sockaddr_ptr, len); - if (ret < 0) { - ret = -errno; - _E("bind() is failed. errno(%d)", errno); - THROW(ret); - } -} - -// LCOV_EXCL_START -int ServerSocket::Listen(int backlog) { - int ret = listen(GetFd(), backlog); - if (ret < 0) { - _E("listen() is failed. errno(%d)", errno); - return -1; - } - - return 0; -} - -void ServerSocket::SetCloseOnExec() { - int flags = fcntl(fd_, F_GETFL, 0); - fcntl(fd_, F_SETFL, flags | FD_CLOEXEC); - _I("Close on exec. fd(%d)", fd_); -} -// LCOV_EXCL_STOP - -void ServerSocket::Close() { - if (fd_ > -1) { - close(fd_); - fd_ = -1; - } -} - -int ServerSocket::RemoveFd() { - int fd = fd_; - fd_ = -1; - return fd; -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/server-socket-internal.hh b/src/server-socket-internal.hh deleted file mode 100644 index ee96155..0000000 --- a/src/server-socket-internal.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef SERVER_SOCKET_INTERNAL_HH_ -#define SERVER_SOCKET_INTERNAL_HH_ - -#include - -#include "client-socket-internal.hh" - -namespace rpc_port { -namespace internal { - -class ServerSocket { - public: - ServerSocket(); - explicit ServerSocket(int fd); - virtual ~ServerSocket(); - - bool IsClosed(); - ClientSocket* Accept(); - int GetFd() const; - void Bind(const std::string& endpoint); - int Listen(int backlog); - void Close(); - void SetCloseOnExec(); - int RemoveFd(); - - private: - int fd_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // SERVER_SOCKET_INTERNAL_HH_ diff --git a/src/stub-internal.cc b/src/stub-internal.cc deleted file mode 100644 index eccdd29..0000000 --- a/src/stub-internal.cc +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 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 "stub-internal.hh" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "aul-internal.hh" -#include "debug-port-internal.hh" -#include "exception-internal.hh" -#include "include/rpc-port.h" -#include "log-private.hh" -#include "peer-cred-internal.hh" -#include "request-internal.hh" -#include "response-internal.hh" - -namespace rpc_port { -namespace internal { -namespace { - -constexpr const char kPortTypeMain[] = "main"; -constexpr const char kPortTypeDelegate[] = "delegate"; -constexpr uid_t kRegularUidMin = 5000; - -int ReceiveRequest(ClientSocket* client, Request** request) { - size_t size = 0; - int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); - if (ret != 0) { - _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - std::vector buf(size); - ret = client->Receive(buf.data(), size); - if (ret != 0) { - _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - tizen_base::Parcel parcel(buf.data(), buf.size()); - *request = new (std::nothrow) Request(); - if (*request == nullptr) { - _E("Out of memory"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - parcel.ReadParcelable(*request); - return 0; -} - -int SendResponse(ClientSocket* client, const Response& response) { - tizen_base::Parcel parcel; - parcel.WriteParcelable(const_cast(response)); - size_t size = parcel.GetDataSize(); - int ret = client->Send(reinterpret_cast(&size), sizeof(size)); - if (ret != 0) { - _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - ret = client->Send(parcel.GetData(), size); - if (ret != 0) { - _E("Send() is failed. error(%d)", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -} // namespace - -std::unordered_set Stub::freed_stubs_; - -Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) { - _D("Stub::Stub()"); - freed_stubs_.erase(this); -} - -Stub::~Stub() { - std::lock_guard lock(GetMutex()); - _D("Stub::~Stub"); - for (auto& p : ports_) { - if (!p->IsDelegate()) - DebugPort::RemoveSession(p->GetFd()); - } - - listener_ = nullptr; - server_.reset(); - if (!port_path_.empty()) { - _W("Delete port path=%s", port_path_.c_str()); - unlink(port_path_.c_str()); - } - - freed_stubs_.insert(this); -} - -int Stub::Listen(IEventListener* ev, int fd) { - if (ev == nullptr) - return RPC_PORT_ERROR_INVALID_PARAMETER; - - std::lock_guard lock(GetMutex()); - if (listener_ != nullptr) { - _E("Already listening!"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE - } - - listener_ = ev; - server_.reset(new Server(fd, this)); - return server_->Listen(); -} - -void Stub::Ignore() { - std::lock_guard lock(GetMutex()); - listener_ = nullptr; -} - -void Stub::AddPrivilege(const std::string& privilege) { - std::lock_guard lock(GetMutex()); - access_controller_->AddPrivilege(privilege); -} - -void Stub::SetTrusted(const bool trusted) { - std::lock_guard lock(GetMutex()); - access_controller_->SetTrusted(trusted); -} - -// LCOV_EXCL_START -std::shared_ptr Stub::FindPort(const std::string& instance) const { - std::lock_guard lock(GetMutex()); - for (auto& p : ports_) { - if (p->GetInstance() == instance && !p->IsDelegate()) { - return p; - } - } - - return {}; -} -// LCOV_EXCL_STOP - -std::shared_ptr Stub::FindDelegatePort( - const std::string& instance) const { - std::lock_guard lock(GetMutex()); - for (auto& p : ports_) { - if (p->GetInstance() == instance && p->IsDelegate()) { - return p; - } - } - - return {}; -} - -const std::string& Stub::GetPortName() const { - return port_name_; -} - -void Stub::RemoveAcceptedPorts(std::string instance) { - std::lock_guard lock(GetMutex()); - auto iter = ports_.begin(); - while (iter != ports_.end()) { - if ((*iter)->GetInstance().compare(instance) == 0) { - LOGI("Close: fd(%d)", (*iter)->GetFd()); - DebugPort::RemoveSession((*iter)->GetFd()); - iter = ports_.erase(iter); - } else { - iter++; - } - } -} - -int Stub::CreatePort() { - if (getenv("AUL_APPID") == nullptr) { - std::string name = Aul::GetName(getpid()); - if (!name.empty()) { - port_path_ = Aul::GetPortPath(name, GetPortName(), getuid()); - int fd = GetFdFromSystemd(); - if (fd > -1) return fd; - - fd = CreateServerSocket(); - if (fd > -1) return fd; - } - } - - int fd = -1; - int ret = aul_rpc_port_usr_create(GetPortName().c_str(), getuid(), &fd); - if (ret != AUL_R_OK) { - // LCOV_EXCL_START - _E("aul_rpc_port_usr_create() is failed. error(%d)", ret); - return RPC_PORT_ERROR_IO_ERROR; - // LCOV_EXCL_STOP - } - - return fd; -} - -int Stub::GetFdFromSystemd() { - int fds = sd_listen_fds(0); - for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fds; ++fd) { - if (sd_is_socket_unix(fd, SOCK_STREAM, 1, port_path_.c_str(), 0) > 0) - return fd; - } - - _E("There is no socket stream"); - return -1; -} - -int Stub::CreateServerSocket() { - try { - ServerSocket socket; - socket.Bind(port_path_); - socket.Listen(128); - return socket.RemoveFd(); - } catch (const Exception& e) { - _E("Exception occurs. error(%s)", e.what()); - return -1; - } -} - -gboolean Stub::AcceptedPort::OnDataReceived(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* stub = static_cast(user_data); - std::lock_guard lock(stub->GetMutex()); - auto* listener = stub->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - int fd = g_io_channel_unix_get_fd(channel); - for (auto& p : stub->ports_) { - if (p->GetFd() == fd && !p->IsDelegate()) { - char buffer[4]; - if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - _W("Socket was disconnected from proxy. fd(%d)", fd); - listener->OnDisconnected(p->GetId(), p->GetInstance()); - stub->RemoveAcceptedPorts(p->GetInstance()); - Aul::NotifyRpcFinished(); - return G_SOURCE_CONTINUE; - } - - int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(), - p.get()); - if (ret != 0) { - _W("Invalid protocol"); - listener->OnDisconnected(p->GetId(), p->GetInstance()); - stub->RemoveAcceptedPorts(p->GetInstance()); - Aul::NotifyRpcFinished(); - return G_SOURCE_CONTINUE; - } - - break; - } - } - - return G_SOURCE_CONTINUE; -} - -gboolean Stub::AcceptedPort::OnSocketDisconnected(GIOChannel* channel, - GIOCondition cond, gpointer user_data) { - auto* stub = static_cast(user_data); - std::lock_guard lock(stub->GetMutex()); - auto* listener = stub->listener_; - if (listener == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - int fd = g_io_channel_unix_get_fd(channel); - _W("Socket was disconnected. fd(%d)", fd); - for (auto& p : stub->ports_) { - if (p->GetFd() == fd) { - listener->OnDisconnected(p->GetId(), p->GetInstance()); - stub->RemoveAcceptedPorts(p->GetInstance()); - Aul::NotifyRpcFinished(); - break; - } - } - - return G_SOURCE_REMOVE; -} - -void Stub::AddAcceptedPort(const std::string& sender_appid, - const std::string& instance, const std::string& port_type, int fd) { - std::lock_guard lock(GetMutex()); - if (port_type == kPortTypeMain) { - auto* main_port = new AcceptedPort(this, false, fd, sender_appid, - instance, true); - ports_.emplace_back(main_port); - return; - } - - auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid, - instance, false); - ports_.emplace_back(delegate_port); - - int main_fd = -1; - for (auto& p : ports_) { - if (p->GetId() == delegate_port->GetId() && - p->GetInstance() == delegate_port->GetInstance() && - p->GetFd() != delegate_port->GetFd()) { - main_fd = p->GetFd(); - break; - } - } - - _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)", - sender_appid.c_str(), instance.c_str(), main_fd, fd); - DebugPort::AddSession(port_name_, sender_appid, main_fd, fd); - listener_->OnConnected(sender_appid, instance); -} - -std::recursive_mutex& Stub::GetMutex() const { - return mutex_; -} - -Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, - std::string id, std::string inst, bool watch) - : Port(fd, std::move(id), std::move(inst)), parent_(parent), - is_delegate_(isDelegate) { - Watch(watch); -} - -// LCOV_EXCL_START -Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, - std::string id, bool watch) - : Port(fd, std::move(id)), parent_(parent), - is_delegate_(isDelegate) { - Watch(watch); -} -// LCOV_EXCL_STOP - -Stub::AcceptedPort::~AcceptedPort() { - if (disconn_source_ > 0) - g_source_remove(disconn_source_); - - if (source_ > 0) - g_source_remove(source_); - - if (channel_ != nullptr) - g_io_channel_unref(channel_); -} - -int Stub::AcceptedPort::Watch(bool receive) { - channel_ = g_io_channel_unix_new(GetFd()); - if (channel_ == nullptr) { - _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - disconn_source_ = g_io_add_watch(channel_, - static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), - OnSocketDisconnected, parent_); - if (disconn_source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - if (!receive) - return 0; - - source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), - OnDataReceived, parent_); - if (source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -Stub::Server::Server(int fd, Stub* parent) - : ServerSocket(fd), - parent_(parent) { -} - -Stub::Server::~Server() { - if (channel_) - g_io_channel_unref(channel_); - - if (source_ > 0) - g_source_remove(source_); -} - -int Stub::Server::Listen() { - channel_ = g_io_channel_unix_new(GetFd()); - if (channel_ == nullptr) { - _E("g_io_channel_unix_new() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), - OnRequestReceived, parent_); - if (source_ == 0) { - _E("g_io_add_watch() is failed"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond, - gpointer user_data) { - auto* stub = static_cast(user_data); - std::lock_guard lock(stub->GetMutex()); - if (stub->listener_ == nullptr) { - _E("Invalid context"); // LCOV_EXCL_LINE - return G_SOURCE_REMOVE; // LCOV_EXCL_LINE - } - - std::shared_ptr client(stub->server_->Accept()); - if (client.get() == nullptr) { - _E("Out of memory"); // LCOV_EXCL_LINE - return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE - } - - Request* request = nullptr; - int ret = ReceiveRequest(client.get(), &request); - if (ret != 0) - return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE - - std::shared_ptr request_auto(request); - std::shared_ptr cred(PeerCred::Get(client->GetFd())); - if (cred.get() == nullptr) { - _E("Failed to create peer credentials"); // LCOV_EXCL_LINE - return G_SOURCE_CONTINUE; // LCOV_EXCL_LINE - } - - std::string app_id = Aul::GetAppId(cred->GetPid()); - auto response_func = [=](int res) -> void { - if (freed_stubs_.find(stub) != freed_stubs_.end()) - return; // LCOV_EXCL_LINE - - Response response(res); - int ret = SendResponse(client.get(), response); - if (ret != 0) - return; // LCOV_EXCL_LINE - - if (res != 0) { - _E("Access denied. fd(%d), pid(%d)", - client->GetFd(), cred->GetPid()); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE - } - - client->SetNonblock(); - int client_fd = client->RemoveFd(); - stub->AddAcceptedPort(app_id, request_auto->GetInstance(), - request_auto->GetPortType(), client_fd); - }; - - int res; - if (cred->GetUid() >= kRegularUidMin) { - if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) { - _E("Reject request. %u:%u", cred->GetUid(), getuid()); // LCOV_EXCL_LINE - res = -1; // LCOV_EXCL_LINE - } else { - stub->access_controller_->CheckAsync(client->GetFd(), app_id, - response_func); - return G_SOURCE_CONTINUE; - } - } else { - _W("Bypass access control. pid(%d), uid(%u)", - cred->GetPid(), cred->GetUid()); - res = 0; - } - - response_func(res); - return G_SOURCE_CONTINUE; -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/stub-internal.hh b/src/stub-internal.hh deleted file mode 100644 index b1ac248..0000000 --- a/src/stub-internal.hh +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#ifndef STUB_INTERNAL_HH_ -#define STUB_INTERNAL_HH_ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ac-internal.hh" -#include "debug-port-internal.hh" -#include "port-internal.hh" -#include "server-socket-internal.hh" - -namespace rpc_port { -namespace internal { - -class Stub { - public: - class IEventListener { - public: - virtual void OnConnected(const std::string& sender, - const std::string& instance) = 0; - virtual void OnDisconnected(const std::string& sender, - const std::string& instance) = 0; - virtual int OnReceived(const std::string& sender, - const std::string& instance, Port* port) = 0; - }; - - explicit Stub(std::string port_name); - virtual ~Stub(); - - int Listen(IEventListener* ev, int fd); - void Ignore(); - void AddPrivilege(const std::string& privilege); - void SetTrusted(const bool trusted); - std::shared_ptr FindPort(const std::string& instance) const; - std::shared_ptr FindDelegatePort(const std::string& instance) const; - const std::string& GetPortName() const; - int CreatePort(); - - private: - class AcceptedPort : public Port { - public: - AcceptedPort(Stub* parent, bool isDelegate, int fd, std::string id, - std::string inst, bool receive); - AcceptedPort(Stub* parent, bool isDelegate, int fd, std::string id, - bool receive); - virtual ~AcceptedPort(); - bool IsDelegate() const { - return is_delegate_; - } - - private: - int Watch(bool receive); - static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - - private: - GIOChannel* channel_ = nullptr; - guint disconn_source_ = 0; - guint source_ = 0; - Stub* parent_; - bool is_delegate_ = false; - }; - - class Server : public ServerSocket { - public: - Server(int fd, Stub* parent); - virtual ~Server(); - - int Listen(); - - private: - static gboolean OnRequestReceived(GIOChannel* channel, GIOCondition cond, - gpointer user_data); - - private: - Stub* parent_; - GIOChannel* channel_ = nullptr; - guint source_ = 0; - }; - - void AddAcceptedPort(const std::string& sender_appid, - const std::string& instance, const std::string& port_type, int fd); - void RemoveAcceptedPorts(std::string instance); - std::recursive_mutex& GetMutex() const; - int GetFdFromSystemd(); - int CreateServerSocket(); - - private: - std::shared_ptr access_controller_ = - std::make_shared(); - std::string port_name_; - std::string port_path_; - std::list> ports_; - IEventListener* listener_ = nullptr; - std::unique_ptr server_; - mutable std::recursive_mutex mutex_; - static std::unordered_set freed_stubs_; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // STUB_INTERNAL_HH_ diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 6353206..4e5b2fa 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -5,8 +5,7 @@ ADD_EXECUTABLE(${TARGET_RPC_PORT_UTIL} ${UTIL_SRCS}) TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT_UTIL} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../ - ${CMAKE_CURRENT_SOURCE_DIR}/../../ - ${CMAKE_CURRENT_SOURCE_DIR}/../../include) + ${CMAKE_CURRENT_SOURCE_DIR}/../include) APPLY_PKG_CONFIG(${TARGET_RPC_PORT_UTIL} PUBLIC AUL_DEPS