Implement rpc_port_proxy_connect_sync() 38/217038/4
authorHwankyu Jhun <h.jhun@samsung.com>
Wed, 6 Nov 2019 00:57:01 +0000 (09:57 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Fri, 8 Nov 2019 00:29:54 +0000 (09:29 +0900)
Change-Id: I655bc3d13124c8623359578842eed431ba81a661
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/rpc-port-internal.h
src/fdbroker-internal.cc
src/fdbroker-internal.h
src/proxy-internal.cc
src/proxy-internal.h
src/rpc-port.cc

index 5a9af2a..3af29e4 100644 (file)
@@ -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
index a8cf58a..c77f2d5 100644 (file)
@@ -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) {
index aac7584..ca489ab 100644 (file)
@@ -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 {
index 3546273..f09a493 100644 (file)
@@ -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<Proxy*>(user_data);
 
index dce40a0..75b30e2 100644 (file)
@@ -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<Port> GetPort() const {
     return main_port_;
index 48d7518..88046bb 100644 (file)
@@ -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<std::recursive_mutex> 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)