The rpc-port sources have been moved to 'src/rpc-port'.
src/
+ src/rpc-port
Change-Id: I93ab201047ba4bfa424baaf2c80bc5dd6cd53e59
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
-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)
+++ /dev/null
-/*
- * 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 <aul.h>
-#include <cynara-client.h>
-#include <cynara-creds-socket.h>
-#include <cynara-error.h>
-#include <dlog.h>
-#include <pkgmgr-info.h>
-
-#include <utility>
-
-#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<Creds> 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<char, decltype(free)*>(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<char, decltype(free)*>(client, free);
-
- return std::make_shared<Creds>(fd, user, client);
- }
-
- int Check(const std::shared_ptr<Creds>& creds,
- const std::string& privilege) const {
- std::lock_guard<std::recursive_mutex> 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<cynara, decltype(cynara_finish)*> 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<AccessController>(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<CompleteCallback, int>(
- std::move(callback), res);
- guint sid = g_idle_add(
- [](gpointer data) -> gboolean {
- auto* cb_data = static_cast<std::pair<CompleteCallback, int>*>(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
+++ /dev/null
-/*
- * 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 <gio/gio.h>
-#include <glib-unix.h>
-#include <glib.h>
-
-#include <functional>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace rpc_port {
-namespace internal {
-
-using CompleteCallback = std::function<void(int)>;
-
-class AccessController : public std::enable_shared_from_this<AccessController> {
- 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<std::string> privileges_;
- std::map<std::string, bool> cache_;
- bool trusted_;
- std::string appid_;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // AC_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <aul.h>
-#include <aul_rpc_port.h>
-#include <aul_proc.h>
-
-#include <memory>
-
-#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<char, decltype(std::free)*> 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<char, decltype(std::free)*> 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
+++ /dev/null
-/*
- * 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 <string>
-
-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_
+++ /dev/null
-/*
- * 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 <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#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<struct sockaddr*>(&sockaddr);
- socklen_t len = static_cast<socklen_t>(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<const unsigned char*>(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<unsigned char*>(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<time_t>(timeout / 1000),
- .tv_usec = static_cast<suseconds_t>((timeout % 1000) * 1000)
- };
- socklen_t len = static_cast<socklen_t>(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
+++ /dev/null
-/*
- * 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 <string>
-
-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_
+++ /dev/null
-/*
- * 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 <utility>
-
-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
+++ /dev/null
-/*
- * 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 <functional>
-#include <shared-queue.hpp>
-#include <thread>
-
-namespace rpc_port {
-namespace internal {
-
-class Job {
- public:
- enum class Type {
- Continue = 0,
- Finish = 1,
- };
-
- using JobHandlerCallback = std::function<Type(void)>;
-
- 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<Job> queue_;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // CYNARA_THREAD_HH_
+++ /dev/null
-/*
- * 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 <aul_app_com.h>
-#include <bundle_internal.h>
-#include <gio/gio.h>
-#include <glib.h>
-#include <parcel.hh>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-
-#include <atomic>
-#include <list>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <utility>
-
-#include <shared-queue.hpp>
-
-#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<Session> FindSession(int port);
- std::shared_ptr<Session> 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<bool> connected_ { false };
- std::unique_ptr<Port> port_;
- GIOChannel* io_ = nullptr;
- guint watch_tag_ = 0;
- std::list<std::shared_ptr<Session>> sessions_;
- std::thread thread_;
- std::atomic<bool> is_running_ { false };
- tizen_base::SharedQueue<std::shared_ptr<tizen_base::Parcel>> queue_;
- mutable std::recursive_mutex mutex_;
- aul_app_com_connection_h conn_ = nullptr;
-};
-
-DebugPortImpl::~DebugPortImpl() {
- Dispose();
-}
-
-void DebugPortImpl::Dispose() {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
- auto iter = std::find_if(sessions_.begin(), sessions_.end(),
- [port](std::shared_ptr<Session>& 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<Session> DebugPortImpl::FindSession(int port) {
- std::lock_guard<std::recursive_mutex> lock(GetMutex());
- for (auto& s : sessions_) {
- if (s->GetMainPort() == port || s->GetDelegatePort() == port)
- return s;
- }
-
- return nullptr;
-}
-
-std::shared_ptr<Session> DebugPortImpl::FindSession(
- const std::string& port_name) {
- std::lock_guard<std::recursive_mutex> 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<const unsigned char*>(buf), size);
-
- queue_.Push(std::make_shared<tizen_base::Parcel>(parcel));
- return 0;
-}
-
-void DebugPortImpl::Init() {
- std::lock_guard<std::recursive_mutex> 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<struct sockaddr*>(&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<GIOCondition>(
- (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<int>(cond));
- auto* debug_port = static_cast<DebugPortImpl*>(data);
- std::lock_guard<std::recursive_mutex> 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<tizen_base::Parcel> parcel = queue_.WaitAndPop();
- int len = parcel->GetDataSize();
- if (len == 0) {
- _W("Done");
- break;
- }
-
- if (!IsConnected())
- continue;
-
- int ret = port_->Write(reinterpret_cast<void*>(&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<tizen_base::Parcel>(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<DebugPortImpl*>(user_data);
- std::string port_name(val);
- if (port_name.empty() || handle->FindSession(port_name) != nullptr) {
- auto* handle = static_cast<DebugPortImpl*>(user_data);
- int fd = handle->Connect();
- if (fd < 0)
- return -1;
-
- std::lock_guard<std::recursive_mutex> 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
+++ /dev/null
-/*
- * 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 <cstdint>
-#include <string>
-
-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_
+++ /dev/null
-/*
- * 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 <utility>
-
-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
+++ /dev/null
-/*
- * 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 <exception>
-#include <string>
-
-#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_
+++ /dev/null
-/*
- * 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 <sys/inotify.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <filesystem>
-#include <utility>
-
-#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<GSourceFunc>(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<FileMonitor*>(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<struct inotify_event*>(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
+++ /dev/null
-/*
- * 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 <gio/gio.h>
-#include <glib.h>
-
-#include <string>
-
-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_
+++ /dev/null
-/*
- * 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 <dlog.h>
-
-#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_
+++ /dev/null
-/*
- * 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<std::mutex> lock(mutex_);
- thread_ = std::make_unique<std::thread>([&]() -> void { ThreadLoop(); });
- cond_.wait(lock, [&] { return thread_ok_; });
-}
-
-MessageSendingThread::~MessageSendingThread() {
- Dispose();
-}
-
-gboolean MessageSendingThread::NotifyOne(gpointer data) {
- auto* sender = static_cast<MessageSendingThread*>(data);
- std::unique_lock<std::mutex> lock(sender->mutex_);
- sender->thread_ok_ = true;
- sender->cond_.notify_one();
- return G_SOURCE_REMOVE;
-}
-
-void MessageSendingThread::ThreadLoop() {
- {
- std::unique_lock<std::mutex> 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<std::mutex> 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
-
+++ /dev/null
-/*
- * 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 <gio/gio.h>
-#include <glib.h>
-
-#include <condition_variable>
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <thread>
-
-#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<std::thread> thread_;
- std::mutex mutex_;
- std::condition_variable cond_;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // MESSAGE_SENDING_THREAD_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <atomic>
-#include <climits>
-#include <limits>
-#include <utility>
-
-#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<int64_t>(time_stamp_.tv_sec));
- parcel->WriteInt64(static_cast<int64_t>(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<time_t>::max();
-
- int64_t tv_nsec = 0;
- parcel->ReadInt64(&tv_nsec);
- time_stamp_.tv_nsec = tv_nsec & std::numeric_limits<long>::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<unsigned int> num { 0 };
- ++num;
- return static_cast<int>(num & INT_MAX);
-}
-
-} // namespace internal
-} // namespace rpc_port
+++ /dev/null
-/*
- * 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 <time.h>
-
-#include <string>
-
-#include <parcel.hh>
-
-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_
+++ /dev/null
-/*
- * 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 <memory>
-#include <utility>
-
-#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<uint8_t*>(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<parcel_h>(const_cast<tizen_base::Parcel*>(&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
+++ /dev/null
-/*
- * 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 <parcel.h>
-
-#include <parcel.hh>
-#include <parcelable.hh>
-
-#include <memory>
-
-#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<ParcelHeader> header_;
- tizen_base::Parcel handle_;
- std::unique_ptr<tizen_base::Parcel> raw_parcel_ { nullptr };
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // PARCEL_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <sys/socket.h>
-#include <sys/types.h>
-
-#include <new>
-
-#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<socklen_t>(sizeof(struct ucred));
- int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
- static_cast<void*>(&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
+++ /dev/null
-/*
- * 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_
+++ /dev/null
-/*
- * 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 <aul_rpc_port.h>
-#include <dlog.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <uuid/uuid.h>
-
-#include <chrono>
-#include <utility>
-
-#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<char*>(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<std::recursive_mutex> lock(mutex_);
- ClearQueue();
- Disconnect();
-}
-
-void Port::Disconnect() {
- IgnoreIOEvent();
-
- std::lock_guard<std::recursive_mutex> 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<char*>(buf);
- int flags;
-
- std::lock_guard<std::recursive_mutex> 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<time_t>(timeout / 1000),
- .tv_usec = static_cast<suseconds_t>((timeout % 1000) * 1000)
- };
- socklen_t len = static_cast<socklen_t>(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<std::recursive_mutex> 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<DelayMessage>(
- static_cast<const char*>(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<const char*>(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<std::weak_ptr<Port>*>(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<std::recursive_mutex> 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<std::recursive_mutex> lock(rw_mutex_);
-
- while (queue_.empty() == false)
- queue_.pop();
-
- IgnoreIOEvent();
- delayed_message_size_ = 0;
-}
-
-void Port::IgnoreIOEvent() {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GIOCondition>(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<Port>(shared_from_this());
- g_source_set_callback(source, reinterpret_cast<GSourceFunc>(OnEventReceived),
- static_cast<gpointer>(ptr), [](gpointer ptr) {
- auto* port = static_cast<std::weak_ptr<Port>*>(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<std::recursive_mutex> 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<DelayMessage> dm) {
- std::lock_guard<std::recursive_mutex> 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
+++ /dev/null
-/*
- * 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 <gio/gio.h>
-#include <glib.h>
-
-#include <algorithm>
-#include <atomic>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <string>
-#include <thread>
-#include <vector>
-
-namespace rpc_port {
-namespace internal {
-
-class Port : public std::enable_shared_from_this<Port> {
- 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<unsigned char> 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<DelayMessage> 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<uint32_t> seq_;
- mutable std::recursive_mutex mutex_;
- mutable std::recursive_mutex rw_mutex_;
- std::queue<std::shared_ptr<DelayMessage>> queue_;
- int delayed_message_size_ = 0;
- GIOChannel* channel_ = nullptr;
- guint source_id_ = 0;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // PORT_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <aul_svc.h>
-#include <dlog.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <uuid.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#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&>(request));
- size_t size = parcel.GetDataSize();
- int ret = client->Send(reinterpret_cast<void*>(&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<void*>(&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<uint8_t*>(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<std::recursive_mutex> 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<std::recursive_mutex> 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> 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<std::recursive_mutex> 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> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
- if (main_port_.get() != nullptr) {
- DebugPort::RemoveSession(main_port_->GetFd());
- main_port_.reset();
- }
-}
-
-int Proxy::Watch() {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
- if (!file_monitor_) return;
-
- file_monitor_->Stop();
-}
-
-void Proxy::SetRealAppId(const std::string& alias_appid) {
- std::lock_guard<std::recursive_mutex> 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<char, decltype(std::free)*> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
- UnsetIdler();
-}
-
-gboolean Proxy::OnTimedOut(gpointer user_data) {
- _E("Timed out");
- auto* ptr = static_cast<std::weak_ptr<Proxy>*>(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<std::recursive_mutex> 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<std::weak_ptr<Proxy>*>(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<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> 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<Proxy::Client> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> 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> 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> 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> Proxy::GetSharedPtr() {
- return shared_from_this();
-}
-
-gpointer Proxy::CreateWeakPtr() {
- auto* ptr = new (std::nothrow) std::weak_ptr<Proxy>(GetSharedPtr());
- return static_cast<gpointer>(ptr);
-}
-
-void Proxy::DestroyWeakPtr(gpointer data) {
- auto* ptr = static_cast<std::weak_ptr<Proxy>*>(data);
- delete ptr;
-}
-
-bool Proxy::HasRequested() const {
- return listener_ != nullptr &&
- (!main_port_ || !delegate_port_ || main_port_->GetFd() > 0);
-}
-
-} // namespace internal
-} // namespace rpc_port
+++ /dev/null
-/*
- * 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 <aul_rpc_port.h>
-#include <gio/gio.h>
-#include <glib-unix.h>
-#include <glib.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-
-#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<Proxy>,
- 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<Port> GetPort() const {
- return main_port_;
- }
-
- std::shared_ptr<Port> 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<Proxy> GetSharedPtr();
- gpointer CreateWeakPtr();
- static void DestroyWeakPtr(gpointer data);
- bool HasRequested() const;
-
- private:
- std::string port_name_;
- std::string port_path_;
- std::shared_ptr<ProxyPort> main_port_;
- std::shared_ptr<ProxyPort> delegate_port_;
- IEventListener* listener_ = nullptr;
- std::string target_appid_;
- std::string real_appid_;
- int fds_[2];
- std::unique_ptr<Client> main_client_;
- std::unique_ptr<Client> delegate_client_;
- gpointer conn_timer_data_ = nullptr;
- gpointer idler_data_ = nullptr;
- mutable std::recursive_mutex mutex_;
- std::unique_ptr<FileMonitor> file_monitor_;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // PROXY_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <utility>
-
-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
+++ /dev/null
-/*
- * 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 <parcel.hh>
-#include <parcelable.hh>
-
-#include <string>
-
-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_
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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 <parcel.hh>
-#include <parcelable.hh>
-
-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_
+++ /dev/null
-/*
- * 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 <aul_proc.h>
-#include <sys/types.h>
-#include <tzplatform_config.h>
-#include <unistd.h>
-
-#include <atomic>
-
-#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<uid_t> __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<Port*>(h);
- std::shared_ptr<PeerCred> 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;
-}
-
+++ /dev/null
-/*
- * 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 <parcel.hh>
-#include <stdint.h>
-#include <string.h>
-
-#include <memory>
-
-#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<rpc_port_parcel_h>(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<internal::Port*>(port);
- {
- std::lock_guard<std::recursive_mutex> 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<unsigned char*>(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<rpc_port_parcel_h>(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<internal::Parcel*>(h);
- tizen_base::Parcel raw_parcel;
- raw_parcel.WriteParcelable(*parcel);
- void* raw = reinterpret_cast<void*>(raw_parcel.GetData());
- uint32_t len = static_cast<uint32_t>(raw_parcel.GetDataSize());
- if (len <= 0)
- return RPC_PORT_ERROR_INVALID_PARAMETER;
-
- internal::Port* pt = static_cast<internal::Port*>(port);
- {
- std::lock_guard<std::recursive_mutex> 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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<bundle_raw, decltype(std::free)*>(raw, std::free);
-
- auto* parcel = static_cast<internal::Parcel*>(h);
- parcel_write_string(parcel->GetHandle(), reinterpret_cast<char*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<long long>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<bundle_raw*>(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<internal::Parcel*>(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<internal::Parcel*>(h);
- uint32_t valid_size = size & UINT32_MAX;
- int ret = parcel_burst_read(parcel->GetHandle(), static_cast<void*>(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<internal::Parcel*>(h);
- uint32_t valid_size = size & UINT32_MAX;
- parcel_burst_write(parcel->GetHandle(), static_cast<const void*>(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<internal::Parcel*>(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<internal::Parcel*>(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<unsigned int>(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<internal::Parcel*>(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<internal::Parcel*>(h);
- auto* parcel_header = parcel->GetParcelHeader();
- if (parcel_header == nullptr)
- return RPC_PORT_ERROR_INVALID_PARAMETER;
-
- *header = reinterpret_cast<rpc_port_parcel_header_h>(
- const_cast<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::Parcel*>(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<unsigned int>(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<rpc_port_parcel_h>(parcel);
- return RPC_PORT_ERROR_NONE;
-}
+++ /dev/null
-/*
- * 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 <aul.h>
-#include <aul_rpc_port.h>
-#include <glib.h>
-
-#include <atomic>
-#include <mutex>
-#include <thread>
-#include <utility>
-
-#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<typename T>
-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<rpc_port_proxy_connected_event_cb>(cb, user_data));
- }
-
- void AddDisconnectedEventListener(rpc_port_proxy_disconnected_event_cb cb,
- void* user_data) {
- disconnected_events_.emplace_back(
- new Event<rpc_port_proxy_disconnected_event_cb>(cb, user_data));
- }
-
- void AddRejectedEventListener(rpc_port_proxy_rejected_event_cb cb,
- void* user_data) {
- rejected_events_.emplace_back(
- new Event<rpc_port_proxy_rejected_event_cb>(cb, user_data));
- }
-
- void AddReceivedEventListener(rpc_port_proxy_received_event_cb cb,
- void* user_data) {
- received_events_.emplace_back(
- new Event<rpc_port_proxy_received_event_cb>(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<bool> destroying_;
- std::list<std::unique_ptr<Event<rpc_port_proxy_connected_event_cb>>>
- connected_events_;
- std::list<std::unique_ptr<Event<rpc_port_proxy_disconnected_event_cb>>>
- disconnected_events_;
- std::list<std::unique_ptr<Event<rpc_port_proxy_rejected_event_cb>>>
- rejected_events_;
- std::list<std::unique_ptr<Event<rpc_port_proxy_received_event_cb>>>
- 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<rpc_port_stub_connected_event_cb>(cb, user_data));
- }
-
- void AddDisconnectedEventListener(rpc_port_stub_disconnected_event_cb cb,
- void* user_data) {
- disconnected_events_.emplace_back(
- new Event<rpc_port_stub_disconnected_event_cb>(cb, user_data));
- }
-
- void AddReceivedEventListener(rpc_port_stub_received_event_cb cb,
- void* user_data) {
- received_events_.emplace_back(
- new Event<rpc_port_stub_received_event_cb>(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<bool> destroying_;
- std::list<std::unique_ptr<Event<rpc_port_stub_connected_event_cb>>>
- connected_events_;
- std::list<std::unique_ptr<Event<rpc_port_stub_disconnected_event_cb>>>
- disconnected_events_;
- std::list<std::unique_ptr<Event<rpc_port_stub_received_event_cb>>>
- 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<Port*>(h);
- uint32_t seq = 0;
- if (DebugPort::IsConnected()) {
- int ret = port->Read(reinterpret_cast<uint32_t*>(&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<Port*>(h);
- uint32_t seq = port->GetSeq();
- if (DebugPort::IsConnected()) {
- int ret = port->Write(reinterpret_cast<void*>(&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<std::shared_ptr<::ProxyExt>*>(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<std::shared_ptr<::ProxyExt>*>(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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port);
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port);
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
- auto* proxy = p->get();
- std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
- rpc_port_h ret_port;
-
- switch (type) {
- case RPC_PORT_PORT_MAIN:
- ret_port = static_cast<rpc_port_h>(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<rpc_port_h>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(p->GetMutex());
- rpc_port_h ret_port;
-
- switch (type) {
- case RPC_PORT_PORT_MAIN:
- ret_port = static_cast<rpc_port_h>(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<rpc_port_h>(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<Port*>(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<Port*>(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<Port*>(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<Port*>(h);
- port->Disconnect();
-
- return RPC_PORT_ERROR_NONE;
-}
--- /dev/null
+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"
+)
--- /dev/null
+/*
+ * 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 <aul.h>
+#include <cynara-client.h>
+#include <cynara-creds-socket.h>
+#include <cynara-error.h>
+#include <dlog.h>
+#include <pkgmgr-info.h>
+
+#include <utility>
+
+#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<Creds> 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<char, decltype(free)*>(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<char, decltype(free)*>(client, free);
+
+ return std::make_shared<Creds>(fd, user, client);
+ }
+
+ int Check(const std::shared_ptr<Creds>& creds,
+ const std::string& privilege) const {
+ std::lock_guard<std::recursive_mutex> 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<cynara, decltype(cynara_finish)*> 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<AccessController>(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<CompleteCallback, int>(
+ std::move(callback), res);
+ guint sid = g_idle_add(
+ [](gpointer data) -> gboolean {
+ auto* cb_data = static_cast<std::pair<CompleteCallback, int>*>(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
--- /dev/null
+/*
+ * 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 <gio/gio.h>
+#include <glib-unix.h>
+#include <glib.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace rpc_port {
+namespace internal {
+
+using CompleteCallback = std::function<void(int)>;
+
+class AccessController : public std::enable_shared_from_this<AccessController> {
+ 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<std::string> privileges_;
+ std::map<std::string, bool> cache_;
+ bool trusted_;
+ std::string appid_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // AC_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <aul.h>
+#include <aul_rpc_port.h>
+#include <aul_proc.h>
+
+#include <memory>
+
+#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<char, decltype(std::free)*> 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<char, decltype(std::free)*> 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
--- /dev/null
+/*
+ * 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 <string>
+
+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_
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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<struct sockaddr*>(&sockaddr);
+ socklen_t len = static_cast<socklen_t>(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<const unsigned char*>(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<unsigned char*>(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<time_t>(timeout / 1000),
+ .tv_usec = static_cast<suseconds_t>((timeout % 1000) * 1000)
+ };
+ socklen_t len = static_cast<socklen_t>(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
--- /dev/null
+/*
+ * 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 <string>
+
+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_
--- /dev/null
+/*
+ * 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 <utility>
+
+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
--- /dev/null
+/*
+ * 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 <functional>
+#include <shared-queue.hpp>
+#include <thread>
+
+namespace rpc_port {
+namespace internal {
+
+class Job {
+ public:
+ enum class Type {
+ Continue = 0,
+ Finish = 1,
+ };
+
+ using JobHandlerCallback = std::function<Type(void)>;
+
+ 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<Job> queue_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // CYNARA_THREAD_HH_
--- /dev/null
+/*
+ * 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 <aul_app_com.h>
+#include <bundle_internal.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <parcel.hh>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <atomic>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <utility>
+
+#include <shared-queue.hpp>
+
+#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<Session> FindSession(int port);
+ std::shared_ptr<Session> 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<bool> connected_ { false };
+ std::unique_ptr<Port> port_;
+ GIOChannel* io_ = nullptr;
+ guint watch_tag_ = 0;
+ std::list<std::shared_ptr<Session>> sessions_;
+ std::thread thread_;
+ std::atomic<bool> is_running_ { false };
+ tizen_base::SharedQueue<std::shared_ptr<tizen_base::Parcel>> queue_;
+ mutable std::recursive_mutex mutex_;
+ aul_app_com_connection_h conn_ = nullptr;
+};
+
+DebugPortImpl::~DebugPortImpl() {
+ Dispose();
+}
+
+void DebugPortImpl::Dispose() {
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ auto iter = std::find_if(sessions_.begin(), sessions_.end(),
+ [port](std::shared_ptr<Session>& 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<Session> DebugPortImpl::FindSession(int port) {
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ for (auto& s : sessions_) {
+ if (s->GetMainPort() == port || s->GetDelegatePort() == port)
+ return s;
+ }
+
+ return nullptr;
+}
+
+std::shared_ptr<Session> DebugPortImpl::FindSession(
+ const std::string& port_name) {
+ std::lock_guard<std::recursive_mutex> 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<const unsigned char*>(buf), size);
+
+ queue_.Push(std::make_shared<tizen_base::Parcel>(parcel));
+ return 0;
+}
+
+void DebugPortImpl::Init() {
+ std::lock_guard<std::recursive_mutex> 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<struct sockaddr*>(&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<GIOCondition>(
+ (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<int>(cond));
+ auto* debug_port = static_cast<DebugPortImpl*>(data);
+ std::lock_guard<std::recursive_mutex> 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<tizen_base::Parcel> parcel = queue_.WaitAndPop();
+ int len = parcel->GetDataSize();
+ if (len == 0) {
+ _W("Done");
+ break;
+ }
+
+ if (!IsConnected())
+ continue;
+
+ int ret = port_->Write(reinterpret_cast<void*>(&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<tizen_base::Parcel>(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<DebugPortImpl*>(user_data);
+ std::string port_name(val);
+ if (port_name.empty() || handle->FindSession(port_name) != nullptr) {
+ auto* handle = static_cast<DebugPortImpl*>(user_data);
+ int fd = handle->Connect();
+ if (fd < 0)
+ return -1;
+
+ std::lock_guard<std::recursive_mutex> 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
--- /dev/null
+/*
+ * 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 <cstdint>
+#include <string>
+
+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_
--- /dev/null
+/*
+ * 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 <utility>
+
+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
--- /dev/null
+/*
+ * 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 <exception>
+#include <string>
+
+#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_
--- /dev/null
+/*
+ * 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 <sys/inotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <filesystem>
+#include <utility>
+
+#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<GSourceFunc>(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<FileMonitor*>(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<struct inotify_event*>(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
--- /dev/null
+/*
+ * 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 <gio/gio.h>
+#include <glib.h>
+
+#include <string>
+
+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_
--- /dev/null
+/*
+ * 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 <dlog.h>
+
+#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_
--- /dev/null
+/*
+ * 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<std::mutex> lock(mutex_);
+ thread_ = std::make_unique<std::thread>([&]() -> void { ThreadLoop(); });
+ cond_.wait(lock, [&] { return thread_ok_; });
+}
+
+MessageSendingThread::~MessageSendingThread() {
+ Dispose();
+}
+
+gboolean MessageSendingThread::NotifyOne(gpointer data) {
+ auto* sender = static_cast<MessageSendingThread*>(data);
+ std::unique_lock<std::mutex> lock(sender->mutex_);
+ sender->thread_ok_ = true;
+ sender->cond_.notify_one();
+ return G_SOURCE_REMOVE;
+}
+
+void MessageSendingThread::ThreadLoop() {
+ {
+ std::unique_lock<std::mutex> 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<std::mutex> 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
+
--- /dev/null
+/*
+ * 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 <gio/gio.h>
+#include <glib.h>
+
+#include <condition_variable>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#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<std::thread> thread_;
+ std::mutex mutex_;
+ std::condition_variable cond_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // MESSAGE_SENDING_THREAD_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <atomic>
+#include <climits>
+#include <limits>
+#include <utility>
+
+#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<int64_t>(time_stamp_.tv_sec));
+ parcel->WriteInt64(static_cast<int64_t>(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<time_t>::max();
+
+ int64_t tv_nsec = 0;
+ parcel->ReadInt64(&tv_nsec);
+ time_stamp_.tv_nsec = tv_nsec & std::numeric_limits<long>::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<unsigned int> num { 0 };
+ ++num;
+ return static_cast<int>(num & INT_MAX);
+}
+
+} // namespace internal
+} // namespace rpc_port
--- /dev/null
+/*
+ * 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 <time.h>
+
+#include <string>
+
+#include <parcel.hh>
+
+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_
--- /dev/null
+/*
+ * 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 <memory>
+#include <utility>
+
+#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<uint8_t*>(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<parcel_h>(const_cast<tizen_base::Parcel*>(&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
--- /dev/null
+/*
+ * 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 <parcel.h>
+
+#include <parcel.hh>
+#include <parcelable.hh>
+
+#include <memory>
+
+#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<ParcelHeader> header_;
+ tizen_base::Parcel handle_;
+ std::unique_ptr<tizen_base::Parcel> raw_parcel_ { nullptr };
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // PARCEL_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <sys/socket.h>
+#include <sys/types.h>
+
+#include <new>
+
+#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<socklen_t>(sizeof(struct ucred));
+ int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
+ static_cast<void*>(&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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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 <aul_rpc_port.h>
+#include <dlog.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#include <chrono>
+#include <utility>
+
+#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<char*>(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<std::recursive_mutex> lock(mutex_);
+ ClearQueue();
+ Disconnect();
+}
+
+void Port::Disconnect() {
+ IgnoreIOEvent();
+
+ std::lock_guard<std::recursive_mutex> 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<char*>(buf);
+ int flags;
+
+ std::lock_guard<std::recursive_mutex> 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<time_t>(timeout / 1000),
+ .tv_usec = static_cast<suseconds_t>((timeout % 1000) * 1000)
+ };
+ socklen_t len = static_cast<socklen_t>(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<std::recursive_mutex> 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<DelayMessage>(
+ static_cast<const char*>(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<const char*>(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<std::weak_ptr<Port>*>(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<std::recursive_mutex> 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<std::recursive_mutex> lock(rw_mutex_);
+
+ while (queue_.empty() == false)
+ queue_.pop();
+
+ IgnoreIOEvent();
+ delayed_message_size_ = 0;
+}
+
+void Port::IgnoreIOEvent() {
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GIOCondition>(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<Port>(shared_from_this());
+ g_source_set_callback(source, reinterpret_cast<GSourceFunc>(OnEventReceived),
+ static_cast<gpointer>(ptr), [](gpointer ptr) {
+ auto* port = static_cast<std::weak_ptr<Port>*>(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<std::recursive_mutex> 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<DelayMessage> dm) {
+ std::lock_guard<std::recursive_mutex> 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
--- /dev/null
+/*
+ * 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 <gio/gio.h>
+#include <glib.h>
+
+#include <algorithm>
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace rpc_port {
+namespace internal {
+
+class Port : public std::enable_shared_from_this<Port> {
+ 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<unsigned char> 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<DelayMessage> 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<uint32_t> seq_;
+ mutable std::recursive_mutex mutex_;
+ mutable std::recursive_mutex rw_mutex_;
+ std::queue<std::shared_ptr<DelayMessage>> queue_;
+ int delayed_message_size_ = 0;
+ GIOChannel* channel_ = nullptr;
+ guint source_id_ = 0;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // PORT_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <aul_svc.h>
+#include <dlog.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <uuid.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#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&>(request));
+ size_t size = parcel.GetDataSize();
+ int ret = client->Send(reinterpret_cast<void*>(&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<void*>(&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<uint8_t*>(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<std::recursive_mutex> 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<std::recursive_mutex> 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> 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<std::recursive_mutex> 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> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ if (main_port_.get() != nullptr) {
+ DebugPort::RemoveSession(main_port_->GetFd());
+ main_port_.reset();
+ }
+}
+
+int Proxy::Watch() {
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ if (!file_monitor_) return;
+
+ file_monitor_->Stop();
+}
+
+void Proxy::SetRealAppId(const std::string& alias_appid) {
+ std::lock_guard<std::recursive_mutex> 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<char, decltype(std::free)*> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ UnsetIdler();
+}
+
+gboolean Proxy::OnTimedOut(gpointer user_data) {
+ _E("Timed out");
+ auto* ptr = static_cast<std::weak_ptr<Proxy>*>(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<std::recursive_mutex> 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<std::weak_ptr<Proxy>*>(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<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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<Proxy::Client> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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> 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> 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> Proxy::GetSharedPtr() {
+ return shared_from_this();
+}
+
+gpointer Proxy::CreateWeakPtr() {
+ auto* ptr = new (std::nothrow) std::weak_ptr<Proxy>(GetSharedPtr());
+ return static_cast<gpointer>(ptr);
+}
+
+void Proxy::DestroyWeakPtr(gpointer data) {
+ auto* ptr = static_cast<std::weak_ptr<Proxy>*>(data);
+ delete ptr;
+}
+
+bool Proxy::HasRequested() const {
+ return listener_ != nullptr &&
+ (!main_port_ || !delegate_port_ || main_port_->GetFd() > 0);
+}
+
+} // namespace internal
+} // namespace rpc_port
--- /dev/null
+/*
+ * 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 <aul_rpc_port.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+#include <glib.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+
+#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<Proxy>,
+ 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<Port> GetPort() const {
+ return main_port_;
+ }
+
+ std::shared_ptr<Port> 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<Proxy> GetSharedPtr();
+ gpointer CreateWeakPtr();
+ static void DestroyWeakPtr(gpointer data);
+ bool HasRequested() const;
+
+ private:
+ std::string port_name_;
+ std::string port_path_;
+ std::shared_ptr<ProxyPort> main_port_;
+ std::shared_ptr<ProxyPort> delegate_port_;
+ IEventListener* listener_ = nullptr;
+ std::string target_appid_;
+ std::string real_appid_;
+ int fds_[2];
+ std::unique_ptr<Client> main_client_;
+ std::unique_ptr<Client> delegate_client_;
+ gpointer conn_timer_data_ = nullptr;
+ gpointer idler_data_ = nullptr;
+ mutable std::recursive_mutex mutex_;
+ std::unique_ptr<FileMonitor> file_monitor_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // PROXY_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <utility>
+
+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
--- /dev/null
+/*
+ * 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 <parcel.hh>
+#include <parcelable.hh>
+
+#include <string>
+
+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_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <parcel.hh>
+#include <parcelable.hh>
+
+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_
--- /dev/null
+/*
+ * 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 <aul_proc.h>
+#include <sys/types.h>
+#include <tzplatform_config.h>
+#include <unistd.h>
+
+#include <atomic>
+
+#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<uid_t> __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<Port*>(h);
+ std::shared_ptr<PeerCred> 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;
+}
+
--- /dev/null
+/*
+ * 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 <parcel.hh>
+#include <stdint.h>
+#include <string.h>
+
+#include <memory>
+
+#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<rpc_port_parcel_h>(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<internal::Port*>(port);
+ {
+ std::lock_guard<std::recursive_mutex> 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<unsigned char*>(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<rpc_port_parcel_h>(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<internal::Parcel*>(h);
+ tizen_base::Parcel raw_parcel;
+ raw_parcel.WriteParcelable(*parcel);
+ void* raw = reinterpret_cast<void*>(raw_parcel.GetData());
+ uint32_t len = static_cast<uint32_t>(raw_parcel.GetDataSize());
+ if (len <= 0)
+ return RPC_PORT_ERROR_INVALID_PARAMETER;
+
+ internal::Port* pt = static_cast<internal::Port*>(port);
+ {
+ std::lock_guard<std::recursive_mutex> 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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<bundle_raw, decltype(std::free)*>(raw, std::free);
+
+ auto* parcel = static_cast<internal::Parcel*>(h);
+ parcel_write_string(parcel->GetHandle(), reinterpret_cast<char*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<long long>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<internal::Parcel*>(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<bundle_raw*>(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<internal::Parcel*>(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<internal::Parcel*>(h);
+ uint32_t valid_size = size & UINT32_MAX;
+ int ret = parcel_burst_read(parcel->GetHandle(), static_cast<void*>(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<internal::Parcel*>(h);
+ uint32_t valid_size = size & UINT32_MAX;
+ parcel_burst_write(parcel->GetHandle(), static_cast<const void*>(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<internal::Parcel*>(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<internal::Parcel*>(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<unsigned int>(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<internal::Parcel*>(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<internal::Parcel*>(h);
+ auto* parcel_header = parcel->GetParcelHeader();
+ if (parcel_header == nullptr)
+ return RPC_PORT_ERROR_INVALID_PARAMETER;
+
+ *header = reinterpret_cast<rpc_port_parcel_header_h>(
+ const_cast<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::ParcelHeader*>(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<internal::Parcel*>(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<unsigned int>(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<rpc_port_parcel_h>(parcel);
+ return RPC_PORT_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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 <aul.h>
+#include <aul_rpc_port.h>
+#include <glib.h>
+
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include <utility>
+
+#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<typename T>
+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<rpc_port_proxy_connected_event_cb>(cb, user_data));
+ }
+
+ void AddDisconnectedEventListener(rpc_port_proxy_disconnected_event_cb cb,
+ void* user_data) {
+ disconnected_events_.emplace_back(
+ new Event<rpc_port_proxy_disconnected_event_cb>(cb, user_data));
+ }
+
+ void AddRejectedEventListener(rpc_port_proxy_rejected_event_cb cb,
+ void* user_data) {
+ rejected_events_.emplace_back(
+ new Event<rpc_port_proxy_rejected_event_cb>(cb, user_data));
+ }
+
+ void AddReceivedEventListener(rpc_port_proxy_received_event_cb cb,
+ void* user_data) {
+ received_events_.emplace_back(
+ new Event<rpc_port_proxy_received_event_cb>(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<bool> destroying_;
+ std::list<std::unique_ptr<Event<rpc_port_proxy_connected_event_cb>>>
+ connected_events_;
+ std::list<std::unique_ptr<Event<rpc_port_proxy_disconnected_event_cb>>>
+ disconnected_events_;
+ std::list<std::unique_ptr<Event<rpc_port_proxy_rejected_event_cb>>>
+ rejected_events_;
+ std::list<std::unique_ptr<Event<rpc_port_proxy_received_event_cb>>>
+ 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<rpc_port_stub_connected_event_cb>(cb, user_data));
+ }
+
+ void AddDisconnectedEventListener(rpc_port_stub_disconnected_event_cb cb,
+ void* user_data) {
+ disconnected_events_.emplace_back(
+ new Event<rpc_port_stub_disconnected_event_cb>(cb, user_data));
+ }
+
+ void AddReceivedEventListener(rpc_port_stub_received_event_cb cb,
+ void* user_data) {
+ received_events_.emplace_back(
+ new Event<rpc_port_stub_received_event_cb>(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<bool> destroying_;
+ std::list<std::unique_ptr<Event<rpc_port_stub_connected_event_cb>>>
+ connected_events_;
+ std::list<std::unique_ptr<Event<rpc_port_stub_disconnected_event_cb>>>
+ disconnected_events_;
+ std::list<std::unique_ptr<Event<rpc_port_stub_received_event_cb>>>
+ 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<Port*>(h);
+ uint32_t seq = 0;
+ if (DebugPort::IsConnected()) {
+ int ret = port->Read(reinterpret_cast<uint32_t*>(&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<Port*>(h);
+ uint32_t seq = port->GetSeq();
+ if (DebugPort::IsConnected()) {
+ int ret = port->Write(reinterpret_cast<void*>(&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<std::shared_ptr<::ProxyExt>*>(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<std::shared_ptr<::ProxyExt>*>(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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port);
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port);
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ std::lock_guard<std::recursive_mutex> 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<std::shared_ptr<::ProxyExt>*>(h);
+ auto* proxy = p->get();
+ std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
+ rpc_port_h ret_port;
+
+ switch (type) {
+ case RPC_PORT_PORT_MAIN:
+ ret_port = static_cast<rpc_port_h>(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<rpc_port_h>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(p->GetMutex());
+ rpc_port_h ret_port;
+
+ switch (type) {
+ case RPC_PORT_PORT_MAIN:
+ ret_port = static_cast<rpc_port_h>(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<rpc_port_h>(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<Port*>(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<Port*>(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<Port*>(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<Port*>(h);
+ port->Disconnect();
+
+ return RPC_PORT_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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<socklen_t>(sizeof(struct sockaddr_un));
+ auto* addr_ptr = reinterpret_cast<struct sockaddr*>(&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<struct sockaddr*>(&sockaddr);
+ socklen_t len = static_cast<socklen_t>(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
--- /dev/null
+/*
+ * 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 <string>
+
+#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_
--- /dev/null
+/*
+ * 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 <aul.h>
+#include <aul_rpc_port.h>
+#include <dlog.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <systemd/sd-daemon.h>
+
+#include <utility>
+#include <vector>
+
+#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<void*>(&size), sizeof(size));
+ if (ret != 0) {
+ _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE
+ return -1; // LCOV_EXCL_LINE
+ }
+
+ std::vector<uint8_t> 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&>(response));
+ size_t size = parcel.GetDataSize();
+ int ret = client->Send(reinterpret_cast<void*>(&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*> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ listener_ = nullptr;
+}
+
+void Stub::AddPrivilege(const std::string& privilege) {
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ access_controller_->AddPrivilege(privilege);
+}
+
+void Stub::SetTrusted(const bool trusted) {
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ access_controller_->SetTrusted(trusted);
+}
+
+// LCOV_EXCL_START
+std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ for (auto& p : ports_) {
+ if (p->GetInstance() == instance && !p->IsDelegate()) {
+ return p;
+ }
+ }
+
+ return {};
+}
+// LCOV_EXCL_STOP
+
+std::shared_ptr<Port> Stub::FindDelegatePort(
+ const std::string& instance) const {
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<Stub*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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<Stub*>(user_data);
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<GIOCondition>(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<Stub*>(user_data);
+ std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
+ if (stub->listener_ == nullptr) {
+ _E("Invalid context"); // LCOV_EXCL_LINE
+ return G_SOURCE_REMOVE; // LCOV_EXCL_LINE
+ }
+
+ std::shared_ptr<ClientSocket> 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> request_auto(request);
+ std::shared_ptr<PeerCred> 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
--- /dev/null
+/*
+ * 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 <glib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+
+#include <list>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
+#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<Port> FindPort(const std::string& instance) const;
+ std::shared_ptr<Port> 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<AccessController> access_controller_ =
+ std::make_shared<AccessController>();
+ std::string port_name_;
+ std::string port_path_;
+ std::list<std::shared_ptr<AcceptedPort>> ports_;
+ IEventListener* listener_ = nullptr;
+ std::unique_ptr<Server> server_;
+ mutable std::recursive_mutex mutex_;
+ static std::unordered_set<Stub*> freed_stubs_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // STUB_INTERNAL_HH_
+++ /dev/null
-/*
- * 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 <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#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<socklen_t>(sizeof(struct sockaddr_un));
- auto* addr_ptr = reinterpret_cast<struct sockaddr*>(&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<struct sockaddr*>(&sockaddr);
- socklen_t len = static_cast<socklen_t>(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
+++ /dev/null
-/*
- * 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 <string>
-
-#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_
+++ /dev/null
-/*
- * 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 <aul.h>
-#include <aul_rpc_port.h>
-#include <dlog.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <systemd/sd-daemon.h>
-
-#include <utility>
-#include <vector>
-
-#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<void*>(&size), sizeof(size));
- if (ret != 0) {
- _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE
- return -1; // LCOV_EXCL_LINE
- }
-
- std::vector<uint8_t> 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&>(response));
- size_t size = parcel.GetDataSize();
- int ret = client->Send(reinterpret_cast<void*>(&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*> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
- listener_ = nullptr;
-}
-
-void Stub::AddPrivilege(const std::string& privilege) {
- std::lock_guard<std::recursive_mutex> lock(GetMutex());
- access_controller_->AddPrivilege(privilege);
-}
-
-void Stub::SetTrusted(const bool trusted) {
- std::lock_guard<std::recursive_mutex> lock(GetMutex());
- access_controller_->SetTrusted(trusted);
-}
-
-// LCOV_EXCL_START
-std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
- std::lock_guard<std::recursive_mutex> lock(GetMutex());
- for (auto& p : ports_) {
- if (p->GetInstance() == instance && !p->IsDelegate()) {
- return p;
- }
- }
-
- return {};
-}
-// LCOV_EXCL_STOP
-
-std::shared_ptr<Port> Stub::FindDelegatePort(
- const std::string& instance) const {
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<Stub*>(user_data);
- std::lock_guard<std::recursive_mutex> 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<Stub*>(user_data);
- std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<GIOCondition>(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<Stub*>(user_data);
- std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
- if (stub->listener_ == nullptr) {
- _E("Invalid context"); // LCOV_EXCL_LINE
- return G_SOURCE_REMOVE; // LCOV_EXCL_LINE
- }
-
- std::shared_ptr<ClientSocket> 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> request_auto(request);
- std::shared_ptr<PeerCred> 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
+++ /dev/null
-/*
- * 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 <glib.h>
-#include <gio/gio.h>
-#include <glib-unix.h>
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <unordered_set>
-
-#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<Port> FindPort(const std::string& instance) const;
- std::shared_ptr<Port> 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<AccessController> access_controller_ =
- std::make_shared<AccessController>();
- std::string port_name_;
- std::string port_path_;
- std::list<std::shared_ptr<AcceptedPort>> ports_;
- IEventListener* listener_ = nullptr;
- std::unique_ptr<Server> server_;
- mutable std::recursive_mutex mutex_;
- static std::unordered_set<Stub*> freed_stubs_;
-};
-
-} // namespace internal
-} // namespace rpc_port
-
-#endif // STUB_INTERNAL_HH_
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