This patch is for linux daemon and service.
The rpc-port creates the socket path without communication with amd if
the caller is a daemon or service. The process name must have "d::" prefix
as below:
e.g. "d::Benchmark"
After this is applied, the rpc-port supports socket activation of system.
The socket path of the daemon is "/run/aul/rpcport/.<proc_name>::<port_name>".
Requires:
- https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/308786/
Change-Id: Ifdd411b2e8b9c745cb9c1cdd9e930df7ab628b9a
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
PKG_CHECK_MODULES(GIO_UNIX_DEPS REQUIRED gio-unix-2.0)
PKG_CHECK_MODULES(GLIB_DEPS REQUIRED glib-2.0)
PKG_CHECK_MODULES(GMOCK_DEPS REQUIRED gmock)
+PKG_CHECK_MODULES(LIBSYSTEMD_DEPS REQUIRED libsystemd)
PKG_CHECK_MODULES(LIBTZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config)
PKG_CHECK_MODULES(PARCEL_DEPS REQUIRED parcel)
PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info)
*/
#include <glib.h>
+#include <sys/types.h>
+#include <unistd.h>
-#include <aul_proc.h>
+#include <rpc-port-internal.h>
#include "BenchmarkStub.h"
#include "log-private.hh"
namespace {
-constexpr const char SERVER_PROC_NAME[] = "org.tizen.appfw.rpc_port.benchmark";
+constexpr const char SERVER_PROC_NAME[] =
+ "d::org.tizen.appfw.rpc_port.benchmark";
namespace bs = rpc_port::BenchmarkStub::stub;
}
void Run() {
- int ret = aul_proc_register(SERVER_PROC_NAME, nullptr);
- if (ret != AUL_R_OK) {
- _E("aul_proc_register() failed (%d)", ret);
+ std::string proc_name = std::string(SERVER_PROC_NAME);
+ if (getuid() >= 5000) proc_name = "u" + proc_name;
+
+ int ret = rpc_port_register_proc_info(proc_name.c_str(), nullptr);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ _E("rpc_port_register_proc_info() failed (%d)", ret);
return;
}
namespace {
-#define SERVER_PROC_NAME "org.tizen.appfw.rpc_port.benchmark"
+#define SERVER_PROC_NAME "d::org.tizen.appfw.rpc_port.benchmark"
#define SERVER_BIN_TIDL "/usr/bin/rpc-port-benchmark-server-tidl"
#define SERVER_BIN_DBUS "/usr/bin/rpc-port-benchmark-server-dbus"
#define SERVER_BIN_GRPC "/usr/bin/rpc-port-benchmark-server-grpc"
} else if (options_->IsGrpc()) {
grpc_proxy_.Connect();
} else {
- proxy_.reset(new bp::Benchmark(&listener_, SERVER_PROC_NAME));
+ std::string proc_name(SERVER_PROC_NAME);
+ if (getuid() >= 5000) proc_name = "u" + proc_name;
+
+ proxy_.reset(new bp::Benchmark(&listener_, proc_name.c_str()));
try {
proxy_->Connect(true);
BuildRequires: pkgconfig(uuid)
BuildRequires: pkgconfig(grpc)
BuildRequires: pkgconfig(protobuf)
+BuildRequires: pkgconfig(libsystemd)
%if 0%{?gcov:1}
BuildRequires: lcov
GIO_DEPS
GIO_UNIX_DEPS
GLIB_DEPS
+ LIBSYSTEMD_DEPS
LIBTZPLATFORM_CONFIG_DEPS
PARCEL_DEPS
PKGMGR_INFO_DEPS
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);
- char* name = nullptr;
- ret = aul_proc_get_name(pid, &name);
- if (ret != AUL_R_OK)
- return "";
-
- std::unique_ptr<char, decltype(std::free)*> name_auto(name, std::free);
- return std::string(name);
+ return GetName(pid);
// LCOV_EXCL_STOP
}
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);
--- /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_);
+ else 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_
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;
}
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) {
- _E("Receive() is failed. error(%d)", ret); // LCOV_EXCL_LINE
- return -1; // LCOV_EXCL_LINE
+ // 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) {
- _E("Out of memory"); // LCOV_EXCL_LINE
- return -1; // LCOV_EXCL_LINE
+ // LCOV_EXCL_START
+ _E("Out of memory");
+ fcntl(client->GetFd(), F_SETFL, flags);
+ return -1;
+ // LCOV_EXCL_STOP
}
ret = client->Receive(buf, size);
// 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) {
- _E("Out of memory"); // LCOV_EXCL_LINE
- return -1; // LCOV_EXCL_LINE
+ // 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() {
Cancel();
}
-int Proxy::Connect(bool sync) {
+int Proxy::MainPortConnect(const std::string& instance, bool sync) {
std::lock_guard<std::recursive_mutex> lock(GetMutex());
fds_[0] = 0;
- fds_[1] = 0;
-
- std::string port_path = Aul::GetPortPath(real_appid_, port_name_,
- rpc_port_get_target_uid());
- std::string instance = GenInstance();
-
- // Main Port
- main_client_.reset(Client::Create(this, port_path));
+ 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
+ if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
if (sync) {
Response* response = nullptr;
ret = ReceiveResponse(main_client_.get(), &response);
- if (ret != 0)
- return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
+ 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
+ _E("Permission denied"); // LCOV_EXCL_LINE
return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE
}
main_client_->SetNonblock();
fds_[0] = main_client_->RemoveFd();
} else {
+ main_client_->SetNonblock();
ret = main_client_->Watch();
- if (ret != 0)
- return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
+ if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
}
- // Delegate Port
- delegate_client_.reset(Client::Create(this, port_path));
+ 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.SetPortType(kPortTypeDelegate);
- ret = SendRequest(delegate_client_.get(), request);
- if (ret != 0)
- 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
if (sync) {
Response* response = nullptr;
ret = ReceiveResponse(delegate_client_.get(), &response);
- if (ret != 0)
- return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
+ 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
+ _E("Permission denied"); // LCOV_EXCL_LINE
return RPC_PORT_ERROR_PERMISSION_DENIED; // LCOV_EXCL_LINE
}
delegate_client_->SetNonblock();
fds_[1] = delegate_client_->RemoveFd();
} else {
+ delegate_client_->SetNonblock();
ret = delegate_client_->Watch();
- if (ret != 0)
- return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
+ 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)
SetRealAppId(target_appid_);
main_port_.reset();
delegate_port_.reset();
+ port_path_ =
+ Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid());
Cancel();
UnsetConnTimer();
- int ret = Aul::PrepareStub(real_appid_, port_name_,
- rpc_port_get_target_uid());
- if (ret != RPC_PORT_ERROR_NONE) {
- listener_ = nullptr;
- return ret;
+ 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;
+ }
}
- ret = Watch();
- if (ret != 0) {
+ if (Watch() != 0) {
listener_ = nullptr; // LCOV_EXCL_LINE
return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
}
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;
+ }
+ }
- int ret = Aul::PrepareStub(real_appid_, port_name_,
- rpc_port_get_target_uid());
+ 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
}
- bool exist = false;
- int retry_count = 20;
+ return RPC_PORT_ERROR_NONE;
+}
+
+bool Proxy::WaitUntilPortCreation() {
+ file_monitor_.reset(new FileMonitor(port_path_));
+ int retry_count = 100;
do {
- exist = Aul::ExistPort(real_appid_, port_name_, rpc_port_get_target_uid());
- if (exist)
- break;
+ if (file_monitor_->Exist()) return true;
- usleep(500 * 1000);
+ usleep(100 * 1000);
retry_count--;
} while (retry_count > 0);
- if (!exist) {
+ if (!file_monitor_->Exist()) {
// LCOV_EXCL_START
- _E("%s:%s is not ready", real_appid_.c_str(), port_name_.c_str());
- listener_ = nullptr;
- return RPC_PORT_ERROR_IO_ERROR;
+ _E("port(%s) of appid(%s) is not ready",
+ port_name_.c_str(), target_appid_.c_str());
+ return false;
// LCOV_EXCL_STOP
}
- ret = Connect(true);
- if (ret != RPC_PORT_ERROR_NONE) {
- listener_ = nullptr; // LCOV_EXCL_LINE
- return ret; // LCOV_EXCL_LINE
- }
-
- 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 RPC_PORT_ERROR_NONE;
+ return true;
}
void Proxy::DisconnectPort() {
int Proxy::Watch() {
std::lock_guard<std::recursive_mutex> lock(GetMutex());
- int ret = aul_rpc_port_usr_add_watch(real_appid_.c_str(), port_name_.c_str(),
- OnPortAppeared, OnPortVanished, this, rpc_port_get_target_uid(),
- &watch_handle_);
- if (ret != AUL_R_OK) {
- _E("aul_rpc_port_usr_add_watch() is failed. error(%d)", ret); // LCOV_EXCL_LINE
- return -1; // LCOV_EXCL_LINE
+ 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;
}
- port_exist_ = Aul::ExistPort(real_appid_, port_name_,
- rpc_port_get_target_uid());
-
- SetConnTimer();
- SetIdler();
return 0;
}
void Proxy::Cancel() {
std::lock_guard<std::recursive_mutex> lock(GetMutex());
- if (watch_handle_) {
- aul_rpc_port_remove_watch(watch_handle_);
- watch_handle_ = nullptr;
- }
+ file_monitor_.reset();
}
void Proxy::SetRealAppId(const std::string& alias_appid) {
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) {
idler_data_ = nullptr;
}
-void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid,
- void* user_data) {
- _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid);
- auto* proxy = static_cast<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
- proxy->UnsetIdler();
-
- if (proxy->watch_handle_ == nullptr) {
- _E("Invalid context");
- return;
- }
-
- auto* listener = proxy->listener_;
- if (listener == nullptr) {
- _E("Invalid context"); // LCOV_EXCL_START
- return; // LCOV_EXCL_START
- }
-
- proxy->Cancel();
+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 = proxy->Connect(false);
+ int ret = Connect(false);
if (ret != RPC_PORT_ERROR_NONE) {
// LCOV_EXCL_START
- proxy->UnsetConnTimer();
- proxy->listener_ = nullptr;
+ UnsetConnTimer();
+ auto* listener = listener_;
+ listener_ = nullptr;
if (ret == RPC_PORT_ERROR_PERMISSION_DENIED)
- listener->OnRejected(proxy->target_appid_, ret);
+ listener->OnRejected(target_appid_, ret);
else
- listener->OnDisconnected(proxy->target_appid_);
+ listener->OnDisconnected(target_appid_);
// LCOV_EXCL_STOP
}
}
-void Proxy::OnPortVanished(const char* app_id, const char* port_name, int pid,
- void* user_data) {
- _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid);
- auto* proxy = static_cast<Proxy*>(user_data);
- std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
- proxy->UnsetIdler();
+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) {
DestroyWeakPtr(proxy->idler_data_);
proxy->idler_data_ = nullptr;
- if (proxy->port_exist_) {
- proxy->OnPortAppeared(proxy->real_appid_.c_str(),
- proxy->port_name_.c_str(), -1, proxy.get());
+ if (proxy->file_monitor_->Exist()) {
+ proxy->OnFileCreated(proxy->port_path_);
} else {
- proxy->OnPortVanished(proxy->real_appid_.c_str(),
- proxy->port_name_.c_str(), -1, proxy.get());
+ proxy->OnFileDeleted(proxy->port_path_);
}
return G_SOURCE_REMOVE;
#define PROXY_INTERNAL_HH_
#include <aul_rpc_port.h>
-#include <glib.h>
#include <gio/gio.h>
#include <glib-unix.h>
+#include <glib.h>
-#include <string>
#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> {
+class Proxy : public std::enable_shared_from_this<Proxy>,
+ public FileMonitor::IEvent {
public:
Proxy();
virtual ~Proxy();
};
private:
- static void OnPortAppeared(const char* app_id, const char* port_name, int pid,
- void* user_data);
- static void OnPortVanished(const char* app_id, const char* port_name, int pid,
- void* user_data);
+ 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();
private:
std::string port_name_;
+ std::string port_path_;
std::shared_ptr<ProxyPort> main_port_;
std::shared_ptr<ProxyPort> delegate_port_;
IEventListener* listener_ = nullptr;
int fds_[2];
std::unique_ptr<Client> main_client_;
std::unique_ptr<Client> delegate_client_;
- aul_rpc_port_watch_h watch_handle_ = nullptr;
gpointer conn_timer_data_ = nullptr;
gpointer idler_data_ = nullptr;
mutable std::recursive_mutex mutex_;
- bool port_exist_ = false;
+ std::unique_ptr<FileMonitor> file_monitor_;
};
} // namespace internal
* limitations under the License.
*/
+#include "include/rpc-port.h"
+
#include <aul.h>
#include <aul_rpc_port.h>
#include <glib.h>
#include <utility>
#include "include/rpc-port-internal.h"
-#include "include/rpc-port.h"
#include "log-private.hh"
#include "port-internal.hh"
#include "proxy-internal.hh"
auto p = static_cast<::StubExt*>(h);
std::lock_guard<std::recursive_mutex> lock(p->GetMutex());
- int fd = -1;
- int ret = aul_rpc_port_usr_create(p->GetPortName().c_str(),
- rpc_port_get_target_uid(), &fd);
- if (ret != AUL_R_OK) {
- _E("aul_rpc_port_usr_create() is failed. error(%d)", ret); // LCOV_EXCL_LINE
+ int fd = p->CreatePort();
+ if (fd < 0)
return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE
- }
return p->Listen(p, fd);
}
* limitations under the License.
*/
+#include "server-socket-internal.hh"
+
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/un.h>
#include <unistd.h>
+#include "exception-internal.hh"
#include "log-private.hh"
-#include "server-socket-internal.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();
}
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);
}
}
+int ServerSocket::RemoveFd() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+}
+
} // namespace internal
} // namespace rpc_port
#ifndef SERVER_SOCKET_INTERNAL_HH_
#define SERVER_SOCKET_INTERNAL_HH_
+#include <string>
+
#include "client-socket-internal.hh"
namespace rpc_port {
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_;
* 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"
-#include "stub-internal.hh"
namespace rpc_port {
namespace internal {
}
}
+int Stub::CreatePort() {
+ if (getenv("AUL_APPID") == nullptr) {
+ std::string name = Aul::GetName(getpid());
+ if (!name.empty()) {
+ std::string endpoint = Aul::GetPortPath(name, GetPortName(), getuid());
+ int fd = GetFdFromSystemd(endpoint);
+ if (fd > -1) return fd;
+
+ fd = CreateServerSocket(endpoint);
+ 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(const std::string& endpoint) {
+ 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, endpoint.c_str(), 0) > 0)
+ return fd;
+ }
+
+ _E("There is no socket stream");
+ return -1;
+}
+
+int Stub::CreateServerSocket(const std::string& endpoint) {
+ try {
+ ServerSocket socket;
+ socket.Bind(endpoint);
+ 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);
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
+ _E("Access denied. fd(%d), pid(%d)",
+ client->GetFd(), cred->GetPid()); // LCOV_EXCL_LINE
+ return; // LCOV_EXCL_LINE
}
client->SetNonblock();
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 {
private:
Stub* parent_;
GIOChannel* channel_ = nullptr;
- guint source_ = 0;;
+ 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(const std::string& endpoint);
+ int CreateServerSocket(const std::string& endpoint);
private:
std::shared_ptr<AccessController> access_controller_ =
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#include <dlog.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+// LCOV_EXCL_START
+extern "C" int __dlog_sec_print(log_id_t log_id, int prio, const char* tag,
+ const char* fmt, ...) {
+ printf("%s:", tag);
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+ return 0;
+}
+
+extern "C" int dlog_vprint(log_priority prio, const char* tag, const char* fmt,
+ va_list ap) {
+ printf("%s:", tag);
+ vprintf(fmt, ap);
+ printf("\n");
+ return 0;
+}
+
+extern "C" int __dlog_print(log_id_t log_id, int prio, const char* tag,
+ const char* fmt, ...) {
+ printf("%s:", tag);
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+ return 0;
+}
+// LCOV_EXCL_STOP
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
--- /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 "mock/inotify_mock.hh"
+
+#include "mock/mock_hook.hh"
+#include "mock/test_fixture.hh"
+
+extern "C" int inotify_add_watch(int fd, const char *pathname, uint32_t mask) {
+ return 1;
+}
+
+extern "C" int inotify_rm_watch(int fd, int wd) {
+ return 0;
+}
--- /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 UNIT_TESTS_MOCK_INOTIFY_MOCK_HH_
+#define UNIT_TESTS_MOCK_INOTIFY_MOCK_HH_
+
+#include <gmock/gmock.h>
+#include <sys/inotify.h>
+
+#include "mock/module_mock.hh"
+
+class InotifyMock : public virtual ModuleMock {
+ public:
+ virtual ~InotifyMock() {}
+
+ MOCK_METHOD3(inotify_add_watch, int(int, const char*, uint32_t));
+ MOCK_METHOD2(inotify_rm_watch, int(int, int));
+};
+
+#endif // UNIT_TESTS_MOCK_INOTIFY_MOCK_HH_
#include "include/rpc-port-internal.h"
#include "unit_tests/mock/aul_mock.hh"
+#include "unit_tests/mock/inotify_mock.hh"
#include "unit_tests/mock/test_fixture.hh"
using ::testing::_;
} // namespace
-class Mocks : public ::testing::NiceMock<AulMock> {};
+class Mocks : public ::testing::NiceMock<AulMock>,
+ public ::testing::NiceMock<InotifyMock> {};
class RpcPortBase : public TestFixture {
public: