From 29d529edf3bff2d8c6f6122e71a6409ddf7ebe89 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 6 Nov 2019 09:57:01 +0900 Subject: [PATCH] Implement rpc_port_proxy_connect_sync() Change-Id: I655bc3d13124c8623359578842eed431ba81a661 Signed-off-by: Hwankyu Jhun --- include/rpc-port-internal.h | 4 ++ src/fdbroker-internal.cc | 168 ++++++++++++++++++++++++++++++++++++++++---- src/fdbroker-internal.h | 3 + src/proxy-internal.cc | 41 +++++++++++ src/proxy-internal.h | 1 + src/rpc-port.cc | 11 +++ 6 files changed, 216 insertions(+), 12 deletions(-) diff --git a/include/rpc-port-internal.h b/include/rpc-port-internal.h index 5a9af2a..3af29e4 100644 --- a/include/rpc-port-internal.h +++ b/include/rpc-port-internal.h @@ -24,8 +24,12 @@ extern "C" { #endif int rpc_port_proxy_create_mockup(rpc_port_proxy_h *h); + int rpc_port_stub_create_mockup(rpc_port_stub_h *h, const char *port_name); +int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char *appid, + const char *port_name); + #ifdef __cplusplus } #endif diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc index a8cf58a..c77f2d5 100644 --- a/src/fdbroker-internal.cc +++ b/src/fdbroker-internal.cc @@ -304,6 +304,142 @@ int FdBroker::Send(const std::string& target_appid, return (*fds)[0]; } +int FdBroker::SendSync(const std::string& target_appid, + const std::string& port_name, + int (*fds)[2]) { + char sender_appid[255] = { 0, }; + int ret; + if (!mock_) { + ret = aul_app_get_appid_bypid(getpid(), sender_appid, sizeof(sender_appid)); + if (ret != AUL_R_OK) { + LOGE("Failed to get application ID. ret(%d)", ret); + return -1; + } + } + + SocketPair main_sock_pair(mock_); + ret = main_sock_pair.Request(target_appid, port_name); + if (ret != 0) + return -1; + + SocketPair delegate_sock_pair(mock_); + ret = delegate_sock_pair.Request(target_appid, port_name); + if (ret != 0) + return -1; + + if (mock_) { + int send_fds[2]; + send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER); + send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER); + + ret = DBusMock::GetInst().Send("TestApp", port_name, send_fds); + if (ret < 0) + return ret; + + (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); + (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); + return (*fds)[0]; + } + + FdList fd_list; + ret = fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER)); + if (ret != 0) + return -1; + + ret = fd_list.Add(delegate_sock_pair.Detach(SocketPair::RECEIVER)); + if (ret != 0) + return -1; + + std::string interface_name = GetInterfaceName(target_appid, port_name); + +#define MAX_CNT 100 +#define MAX_SLEEP 100 +#define MIN_SLEEP 50 +#define BASE_SLEEP (1000 * 1000) + GDBusMessage* reply; + GError* err = nullptr; + struct timespec try_sleep_time = { 0, MIN_SLEEP * BASE_SLEEP }; + struct timespec start_time = { 0, }; + struct timespec end_time = { 0, }; + int max_timeout = MAX_CNT * MAX_SLEEP; + + do { + clock_gettime(CLOCK_MONOTONIC, &start_time); + GDBusMessage* msg = g_dbus_message_new_method_call(interface_name.c_str(), + RPC_PORT_OBJECT_PATH, interface_name.c_str(), "send_message"); + if (msg == nullptr) { + LOGE("g_dbus_message_new_method_call() is failed"); + return -1; + } + + g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw()); + + reply = g_dbus_connection_send_message_with_reply_sync( + DBusConnectionManager::GetInst().GetConnection(), + msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 500, nullptr, nullptr, &err); + clock_gettime(CLOCK_MONOTONIC, &end_time); + g_object_unref(msg); + + if (reply && !g_dbus_message_to_gerror(reply, &err)) + break; + + if (reply == nullptr) { + LOGE("g_dbus_connection_send_message_with_reply_sync() is failed"); + if (err) { + LOGE("error(%s)", err->message); + g_error_free(err); + } + } else if (g_dbus_message_to_gerror(reply, &err)) { + LOGE("error(%s) was set", err->message); + g_error_free(err); + g_object_unref(reply); + } + err = nullptr; + + max_timeout -= (((end_time.tv_sec - start_time.tv_sec) * 1000) + + ((end_time.tv_nsec - start_time.tv_nsec) / BASE_SLEEP)); + if (max_timeout <= 0) + break; + + nanosleep(&try_sleep_time, 0); + max_timeout -= (try_sleep_time.tv_nsec / BASE_SLEEP); + if (max_timeout <= 0) + break; + + try_sleep_time.tv_nsec *= 2; + if (try_sleep_time.tv_nsec > (MAX_SLEEP * BASE_SLEEP)) + try_sleep_time.tv_nsec = MAX_SLEEP * BASE_SLEEP; + + LOGD("Retry"); + } while (max_timeout > 0); + + if (max_timeout <= 0) { + LOGE("Timed out"); + return -1; + } + + GVariant* reply_body = g_dbus_message_get_body(reply); + if (reply_body == nullptr) { + LOGE("g_dbus_message_get_body() is failed"); + g_object_unref(reply); + return -1; + } + + g_variant_get(reply_body, "(i)", &ret); + if (ret != 0) { + LOGE("Access Denied[sender_appid: %s, result: %d]", sender_appid, ret); + g_object_unref(reply); + return -EILLEGALACCESS; + } + + LOGD("[Reply: %d]", ret); + + (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); + (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); + + return (*fds)[0]; +} + void FdBroker::ReceiveMessage(const char* sender_appid, GDBusMethodInvocation* invocation) { GDBusMessage* msg; @@ -557,27 +693,20 @@ void FdBroker::OnNameVanished(GDBusConnection *connection, int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, const std::string& port_name) { - int r; - if (ev == nullptr) return -1; - if (!mock_) { - r = aul_rpc_port_prepare_stub(target_appid.c_str(), port_name.c_str()); - if (r != AUL_R_OK) { - LOGE("Failed to prepare stub %s:%s [ret : %d]", - target_appid.c_str(), port_name.c_str(), r); - return r; - } - } + int ret = Prepare(target_appid, port_name); + if (ret < 0) + return ret; watcher_ = ev; watch_appid_ = target_appid; watch_port_name_ = port_name; if (mock_) { - r = DBusMock::GetInst().Watch(ev, target_appid, port_name); - if (r < 0) + ret = DBusMock::GetInst().Watch(ev, target_appid, port_name); + if (ret < 0) return -1; return 0; @@ -608,6 +737,21 @@ int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, return 0; } +int FdBroker::Prepare(const std::string& target_appid, + const std::string& port_name) { + if (!mock_) { + int ret = aul_rpc_port_prepare_stub(target_appid.c_str(), + port_name.c_str()); + if (ret != AUL_R_OK) { + LOGE("Failed to prepare stub %s:%s [ret : %d]", + target_appid.c_str(), port_name.c_str(), ret); + return ret; + } + } + + return 0; +} + void FdBroker::OnResultReceived(GObject* source_object, GAsyncResult* res, gpointer user_data) { diff --git a/src/fdbroker-internal.h b/src/fdbroker-internal.h index aac7584..ca489ab 100644 --- a/src/fdbroker-internal.h +++ b/src/fdbroker-internal.h @@ -65,6 +65,9 @@ class FdBroker { AccessController& GetAccessController(); int Watch(IEventWatcher* ev, const std::string& target_appid, const std::string& port_name); + int Prepare(const std::string& target_appid, const std::string& port_name); + int SendSync(const std::string& target_appid, const std::string& port_name, + int (*fds)[2]); private: class DBusConnectionManager { diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index 3546273..f09a493 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -179,6 +179,47 @@ int Proxy::Connect(std::string appid, std::string port_name, return RPC_PORT_ERROR_NONE; } +int Proxy::ConnectSync(std::string appid, std::string port_name, + IEventListener* ev) { + if (ev == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + if (listener_ != nullptr) { + LOGW("Already connected"); + return RPC_PORT_ERROR_INVALID_PARAMETER; + } + + listener_ = ev; + target_appid_ = std::move(appid); + port_name_ = std::move(port_name); + + int ret = fd_broker_.Prepare(target_appid_, port_name_); + if (ret < 0) { + listener_ = nullptr; + if (ret == -EILLEGALACCESS) + return RPC_PORT_ERROR_PERMISSION_DENIED; + + return RPC_PORT_ERROR_IO_ERROR; + } + + fds_[0] = 0; + fds_[1] = 0; + ret = fd_broker_.SendSync(target_appid_, port_name_, &fds_); + if (ret <= 0) { + listener_ = nullptr; + if (ret == -EILLEGALACCESS) + return RPC_PORT_ERROR_PERMISSION_DENIED; + + return RPC_PORT_ERROR_IO_ERROR; + } + + main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); + delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); + listener_->OnConnected(target_appid_, main_port_.get()); + + return RPC_PORT_ERROR_NONE; +} + gboolean Proxy::DbusNameTimeout(gpointer user_data) { Proxy* obj = static_cast(user_data); diff --git a/src/proxy-internal.h b/src/proxy-internal.h index dce40a0..75b30e2 100644 --- a/src/proxy-internal.h +++ b/src/proxy-internal.h @@ -44,6 +44,7 @@ class Proxy : public FdBroker::IEventWatcher { }; int Connect(std::string appid, std::string port_name, IEventListener* ev); + int ConnectSync(std::string appid, std::string port_name, IEventListener* ev); std::shared_ptr GetPort() const { return main_port_; diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 48d7518..88046bb 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -232,6 +232,17 @@ RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, return p->Connect(appid, port, p); } +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<::ProxyExt*>(h); + std::lock_guard lock(p->GetMutex()); + + return p->ConnectSync(appid, port, p); +} + 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) -- 2.7.4