Support sending exception feature 74/288274/9
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 14 Feb 2023 09:26:45 +0000 (09:26 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 15 Feb 2023 10:17:10 +0000 (10:17 +0000)
This patch supports sending a remote exception. The server can throw
the remote exception to the client.

Change-Id: I6752837e89b33ad3ed4b09a5f78d8d6c13c6a979
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
13 files changed:
idlc/gen/version2/c_body_generator_base.cc
idlc/gen/version2/c_proxy_body_generator.cc
idlc/gen/version2/c_proxy_body_generator.hh
idlc/gen/version2/c_proxy_body_generator_cb.hh
idlc/gen/version2/c_proxy_header_generator.cc
idlc/gen/version2/c_proxy_header_generator.hh
idlc/gen/version2/c_proxy_header_generator_cb.hh
idlc/gen/version2/c_stub_body_generator.cc
idlc/gen/version2/c_stub_body_generator.hh
idlc/gen/version2/c_stub_body_generator_cb.hh
idlc/gen/version2/c_stub_header_generator.cc
idlc/gen/version2/c_stub_header_generator.hh
idlc/gen/version2/c_stub_header_generator_cb.hh

index 7fc0817..ce2d50d 100644 (file)
@@ -1167,6 +1167,15 @@ void CBodyGeneratorBase::GenParameterMap() {
   for (auto& block : GetDocument().GetBlocks()) {
     if (block->GetType() == Block::TYPE_INTERFACE) {
       auto& iface = static_cast<const Interface&>(*block);
+      AddParameterType(
+          std::make_shared<ParameterType>(
+            new BaseType(iface.GetID() + "_remote_exception", "", true),
+            ParameterType::Direction::OUT));
+      AddParameterType(
+          std::make_shared<ParameterType>(
+            new BaseType(iface.GetID() + "_remote_exception", "", true),
+            ParameterType::Direction::IN));
+
       for (const auto& decl : iface.GetDeclarations()) {
         for (const auto& param : decl->GetParameters()) {
           auto& type = param->GetParameterType().GetBaseType();
index 5fcb3ca..1731146 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "idlc/gen/version2/c_proxy_body_generator.hh"
 
+#include <utility>
+
 #include "idlc/gen/version2/c_proxy_body_generator_cb.hh"
 
 namespace tidl {
@@ -76,6 +78,7 @@ void CProxyBodyGenerator::GenInterfaceDefinition(std::ofstream& stream) {
       GenInterfaceDelegateDefinition(stream, iface, *decl);
     }
 
+    GenInterfaceRemoteExceptionDefinition(stream, iface);
     GenInterfaceBaseDefinition(stream, iface);
   }
 }
@@ -90,6 +93,15 @@ void CProxyBodyGenerator::GenInterfaceDelegateDefinition(std::ofstream& stream,
       .Out(stream);
 }
 
+void CProxyBodyGenerator::GenInterfaceRemoteExceptionDefinition(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_DEF)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 void CProxyBodyGenerator::GenInterfaceBaseDefinition(std::ofstream& stream,
     const Interface& iface) {
   ReplaceAll(CB_INTERFACE_BASE_DEF)
@@ -116,6 +128,7 @@ void CProxyBodyGenerator::GenInterface(std::ofstream& stream) {
 
     GenInterfaceDelegateTable(stream, iface);
     GenInterfaceMethodEnumBase(stream, iface);
+    GenInterfaceRemoteExceptionBase(stream, iface);
     GenInterfaceBase(stream, iface);
 
     for (const auto& decl : iface.GetDeclarations()) {
@@ -348,6 +361,15 @@ void CProxyBodyGenerator::GenInterfaceBase(std::ofstream& stream,
       .Out(stream);
 }
 
+void CProxyBodyGenerator::GenInterfaceRemoteExceptionBase(std::ofstream& stream,
+    const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_BASE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 void CProxyBodyGenerator::GenInterfaceMethodEnumBase(std::ofstream& stream,
     const Interface& iface) {
   std::string enums = GetHandlePrefix() + "_" + iface.GetID() +
@@ -403,7 +425,8 @@ void CProxyBodyGenerator::GenInterfaceDelegateBase(std::ofstream& stream,
     const Interface& iface, const Declaration& decl) {
   std::string enum_value = GetHandlePrefix() + "_" + iface.GetID() +
       "_DELEGATE_" + decl.GetID();
-  std::string delegate_args_free = GenDelegateArgsFree(iface, decl);
+  bool has_free = false;
+  std::string delegate_args_free = GenDelegateArgsFree(iface, decl, &has_free);
 
   ReplaceAll(CB_INTERFACE_DELEGATE_BASE)
       .Change("<PREFIX>", GetHandlePrefix())
@@ -479,7 +502,7 @@ std::string CProxyBodyGenerator::GenDelegateArgsDecl(const Interface& iface,
 }
 
 std::string CProxyBodyGenerator::GenDelegateArgsFree(const Interface& iface,
-    const Declaration& decl) {
+    const Declaration& decl, bool* has_free) {
   std::string code;
   for (const auto& param : decl.GetParameters()) {
     auto& param_type = param->GetParameterType();
@@ -492,12 +515,15 @@ std::string CProxyBodyGenerator::GenDelegateArgsFree(const Interface& iface,
           .Change("<PREFIX>", GetHandlePrefix())
           .Change("<NAME>", GetFullNameFromType(type, iface))
           .Change("<ARG>", param->GetID());
+      *has_free = true;
     } else if (type.ToString() == "bundle") {
       code += ReplaceAll(CB_INTERFACE_DELEGATE_BUNDLE_ARG_FREE,
           "<ARG>", param->GetID());
+      *has_free = true;
     } else if (type.ToString() == "string" || type.ToString() == "file") {
       code += ReplaceAll(CB_INTERFACE_DELEGATE_STRING_ARG_FREE,
           "<ARG>", param->GetID());
+      *has_free = true;
     }
   }
 
index 5785f1f..29d0420 100644 (file)
@@ -40,6 +40,8 @@ class CProxyBodyGenerator : public CBodyGeneratorBase {
   void GenInterfaceDefinition(std::ofstream& stream);
   void GenInterfaceDelegateDefinition(std::ofstream& stream,
       const Interface& iface, const Declaration& decl);
+  void GenInterfaceRemoteExceptionDefinition(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceBaseDefinition(std::ofstream& stream,
       const Interface& iface);
   void GenInterface(std::ofstream& stream);
@@ -63,6 +65,8 @@ class CProxyBodyGenerator : public CBodyGeneratorBase {
   void GenInterfaceMethodBase(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
   void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionBase(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceMethodEnumBase(std::ofstream& stream,
       const Interface& iface);
   void GenInterfaceDelegateTable(std::ofstream& stream, const Interface& iface);
@@ -74,7 +78,7 @@ class CProxyBodyGenerator : public CBodyGeneratorBase {
   std::string GenDelegateArgsDecl(const Interface& iface,
       const Declaration& decl);
   std::string GenDelegateArgsFree(const Interface& iface,
-      const Declaration& decl);
+      const Declaration& decl, bool* has_free);
   void GenInterfaceDelegateEnumBase(std::ofstream& stream,
       const Interface& iface);
   void GenDelegateDefinition(std::ofstream& stream);
index a9c5a95..e968723 100644 (file)
@@ -643,6 +643,12 @@ static void __<PREFIX>_<NAME>_consume_command(rpc_port_h port, int seq_num, rpc_
 
     rpc_port_unit_map_read_int(map, "[METHOD]", &cmd);
     if (cmd == <UPPERCASE_PREFIX>_<UPPERCASE_NAME>_METHOD_RESULT_) {
+      if (__<PREFIX>_<NAME>_remote_exception != nullptr)
+        <PREFIX>_<NAME>_remote_exception_destroy(__<PREFIX>_<NAME>_remote_exception);
+
+      __<PREFIX>_<NAME>_remote_exception = nullptr;
+      rpc_port_unit_map_read_<NAME>_remote_exception(map, "[REMOTE_EXCEPTION]", &__<PREFIX>_<NAME>_remote_exception);
+
       *unit_map = map;
       return;
     }
@@ -1178,6 +1184,167 @@ R"__c_cb(
 h->delegates = g_list_append(h->delegates, <ARG>);
 )__c_cb";
 
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_DEF[] =
+R"__c_cb(
+typedef struct <PREFIX>_<NAME>_remote_exception_s {
+  rpc_port_parcelable_t parcelable;
+  int cause;
+  char *message;
+} <PREFIX>_<NAME>_remote_exception_t;
+
+static __thread <PREFIX>_<NAME>_remote_exception_h __<PREFIX>_<NAME>_remote_exception;
+
+static int <PREFIX>_<NAME>_remote_exception_create(<PREFIX>_<NAME>_remote_exception_h *h);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] =
+R"__c_cb(
+static void __<PREFIX>_<NAME>_remote_exception_to(rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_remote_exception_h h = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_unit_map_write_int(map, "cause", h->cause);
+  rpc_port_unit_map_write_string(map, "message", h->message);
+  rpc_port_parcel_write(parcel, &map->parcelable, map);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void __<PREFIX>_<NAME>_remote_exception_from(rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_remote_exception_h h = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+  rpc_port_unit_map_read_int(map, "cause", &h->cause);
+  rpc_port_unit_map_read_string(map, "message", &h->message);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static int <PREFIX>_<NAME>_remote_exception_create(<PREFIX>_<NAME>_remote_exception_h *h)
+{
+  <PREFIX>_<NAME>_remote_exception_h exception;
+
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  exception = calloc(1, sizeof(<PREFIX>_<NAME>_remote_exception_t));
+  if (exception == nullptr) {
+    _E("calloc() is failed");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  exception->parcelable.to = __<PREFIX>_<NAME>_remote_exception_to;
+  exception->parcelable.from = __<PREFIX>_<NAME>_remote_exception_from;
+
+  *h = exception;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_get_remote_exception(<PREFIX>_<NAME>_remote_exception_h *h)
+{
+  rpc_port_unit_map_h map;
+  int ret;
+
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (__<PREFIX>_<NAME>_remote_exception == nullptr) {
+    _W("There is no exceptions");
+    *h = nullptr;
+    return RPC_PORT_ERROR_NONE;
+  }
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = rpc_port_unit_map_write_<NAME>_remote_exception(map, "clone", __<PREFIX>_<NAME>_remote_exception);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to write remote exception. error(%d)", ret);
+    rpc_port_unit_map_destroy(map);
+    return ret;
+  }
+
+  ret = rpc_port_unit_map_read_<NAME>_remote_exception(map, "clone", h);
+  rpc_port_unit_map_destroy(map);
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_get_cause(<PREFIX>_<NAME>_remote_exception_h h, int *cause)
+{
+  if (h == nullptr || cause == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *cause = h->cause;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_get_message(<PREFIX>_<NAME>_remote_exception_h h, char **message)
+{
+  if (h == nullptr || message == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *message = strdup(h->message);
+  if (*message == nullptr) {
+    _E("strdup() is failed");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_destroy(<PREFIX>_<NAME>_remote_exception_h h)
+{
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (h->message)
+    free(h->message);
+
+  free(h);
+
+  return RPC_PORT_ERROR_NONE;
+}
+)__c_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index 5faf706..8841359 100644 (file)
@@ -48,6 +48,7 @@ void CProxyHeaderGenerator::GenInterfaceHandles(std::ofstream& stream) {
 
     auto& iface = static_cast<const Interface&>(*b);
     GenInterfaceHandle(stream, iface);
+    GenInterfaceRemoteExceptionHandle(stream, iface);
     for (const auto& d : iface.GetDeclarations()) {
       if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
         continue;
@@ -66,6 +67,15 @@ void CProxyHeaderGenerator::GenInterfaceHandle(std::ofstream& stream,
       .Out(stream);
 }
 
+void CProxyHeaderGenerator::GenInterfaceRemoteExceptionHandle(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_HANDLE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 void CProxyHeaderGenerator::GenInterfaceDelegateHandle(std::ofstream& stream,
     const Interface& iface, const Declaration& decl) {
   ReplaceAll(CB_INTERFACE_DELEGATE_HANDLE)
@@ -95,6 +105,7 @@ void CProxyHeaderGenerator::GenInterface(std::ofstream& stream,
     GenInterfaceDelegateBase(stream, iface, *d);
   }
 
+  GenInterfaceRemoteExceptionBase(stream, iface);
   GenInterfaceBase(stream, iface);
 
   for (const auto& d : iface.GetDeclarations()) {
@@ -114,6 +125,15 @@ void CProxyHeaderGenerator::GenInterfaceBase(std::ofstream& stream,
       .Out(stream);
 }
 
+void CProxyHeaderGenerator::GenInterfaceRemoteExceptionBase(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_BASE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 std::string CProxyHeaderGenerator::GenDelegateParams(const Interface& iface,
     const Declaration& decl) {
   std::string params;
index 9b69734..d7cb19f 100644 (file)
@@ -36,11 +36,15 @@ class CProxyHeaderGenerator : public CHeaderGeneratorBase {
  private:
   void GenInterfaceHandles(std::ofstream& stream);
   void GenInterfaceHandle(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionHandle(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateHandle(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
 
   void GenInterfaces(std::ofstream& stream);
   void GenInterface(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionBase(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateBase(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
   void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
index a7e66ea..ceec0ff 100644 (file)
@@ -340,6 +340,65 @@ R"__c_cb(
 <RETURN_TYPE><PREFIX>_<NAME>_invoke_<METHOD_NAME>(<PREFIX>_<NAME>_h h<METHOD_PARAMS>);
 )__c_cb";
 
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_HANDLE[] =
+R"__c_cb(
+/**
+ * @breif The <PREFIX> <NAME> remote exception handle.
+ */
+typedef struct <PREFIX>_<NAME>_remote_exception_s *<PREFIX>_<NAME>_remote_exception_h;
+)__c_cb";
+
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] =
+R"__c_cb(
+/**
+ * @brief Gets the remote exception handle.
+ * @details If the return value is nullptr, there is no exceptions.
+ * @remarks The handle should be released using <PREFIX>_<NAME>_remote_exception_destroy(), if it's no longer needed.
+ * @param[out] h The <PREFIX> <NAME> remote exception handle.
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @see <PREFIX>_<NAME>_remote_exception_destroy();
+ */
+int <PREFIX>_<NAME>_get_remote_exception(<PREFIX>_<NAME>_remote_exception_h *h);
+
+/**
+ * @brief Gets the cause of the exception.
+ * @param[in] h The <PREFIX> <NAME> remote exception handle.
+ * @param[out] cause The cause
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_remote_exception_get_cause(<PREFIX>_<NAME>_remote_exception_h h, int *cause);
+
+/**
+ * @brief Gets the detail message of the exception.
+ * @remarks The @c message should be released if it's no longer needed.
+ * @param[in] h The <PREFIX> <NAME> remote exception handle.
+ * @param[out] message The detail message
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_remote_exception_get_message(<PREFIX>_<NAME>_remote_exception_h, char **message);
+
+/**
+ * @brief Destroys the remote exception handle.
+ * @param[in] h The <PREFIX> <NAME> remote exception handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_remote_exception_destroy(<PREFIX>_<NAME>_remote_exception_h h);
+)__c_cb";
+
 }  // namespace version2
 }  // namespace tidl
 
index ca08baf..adb29f8 100644 (file)
@@ -202,6 +202,7 @@ void CStubBodyGenerator::GenInterfaceDef(std::ofstream& stream,
     GenInterfaceCallbackPortCheckDef(stream, iface);
 
   GenInterfaceContextDef(stream, iface);
+  GenInterfaceRemoteExceptionDefinition(stream, iface);
   GenInterfaceBaseDef(stream, iface);
 }
 
@@ -239,6 +240,16 @@ void CStubBodyGenerator::GenInterfaceContextDef(std::ofstream& stream,
   stream << SmartIndent(code);
 }
 
+// @see #CB_INTERFACE_REMOTE_EXCEPTION_DEF
+void CStubBodyGenerator::GenInterfaceRemoteExceptionDefinition(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_DEF)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 // @see #CB_INTERFACE_BASE_DEF
 void CStubBodyGenerator::GenInterfaceBaseDef(std::ofstream& stream,
     const Interface& iface) {
@@ -279,6 +290,7 @@ void CStubBodyGenerator::GenInterface(std::ofstream& stream, const Interface& if
 
   GenInterfaceMethodTable(stream, iface);
   GenInterfaceContextBase(stream, iface);
+  GenInterfaceRemoteExceptionBase(stream, iface);
 
   if (has_delegate)
     GenInterfaceCallbackPortCheck(stream, iface);
@@ -297,6 +309,16 @@ void CStubBodyGenerator::GenInterfaceContextBase(std::ofstream& stream,
   stream << SmartIndent(code);
 }
 
+// @see #CB_INTERFACE_REMOTE_EXCEPTION_BASE
+void CStubBodyGenerator::GenInterfaceRemoteExceptionBase(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_BASE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 std::string CStubBodyGenerator::GenDelegateParams(const Interface& iface,
     const Declaration& decl) {
   std::string params;
@@ -436,9 +458,11 @@ std::string CStubBodyGenerator::GenMethodUnitMapRead(const Interface& iface,
 
 // @see #CB_INTERFACE_METHOD_CALLBACK_INVOKE
 std::string CStubBodyGenerator::GenMethodHandlerCallbackInvoke(
-    const Declaration& decl) {
+    const Interface& iface, const Declaration& decl) {
   std::string code(ReplaceAll(CB_INTERFACE_METHOD_CALLBACK_INVOKE,
       "<METHOD_NAME>", decl.GetID()));
+  code = ReplaceAll(code, "<PREFIX>", GetHandlePrefix());
+  code = ReplaceAll(code, "<NAME>", iface.GetID());
 
   if (decl.GetMethodType() == Declaration::MethodType::SYNC)
     code = ReplaceAll(code, "<RES_SET>", "res_ = ");
@@ -546,7 +570,9 @@ std::string CStubBodyGenerator::GenMethodUnitMapWrite(const Interface& iface,
 
   code += GenMethodUnitMapWriteBase(iface, decl.GetType(), "[RESULT]", "res_");
 
-  code += std::string(CB_INTERFACE_METHOD_PARCEL_WRITE_POST);
+  code += ReplaceAll(CB_INTERFACE_METHOD_PARCEL_WRITE_POST)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID());
 
   return RemoveLine(code);
 }
@@ -621,7 +647,7 @@ void CStubBodyGenerator::GenInterfaceMethodHandlerBase(std::ofstream& stream,
       { "<METHOD_UNIT_MAP_READ>",
           GenMethodUnitMapRead(iface, decl) },
       { "<METHOD_HANDLER_CALLBACK_INVOKE>",
-          GenMethodHandlerCallbackInvoke(decl) },
+          GenMethodHandlerCallbackInvoke(iface, decl) },
       { "<METHOD_UNIT_MAP_WRITE>",
           GenMethodUnitMapWrite(iface, decl) },
       { "<METHOD_HANDLER_ARGS_FREE>", GenMethodHandlerArgsFree(iface, decl) }
index 639f476..90b73ba 100644 (file)
@@ -48,6 +48,8 @@ class CStubBodyGenerator : public CBodyGeneratorBase {
   void GenInterfaceDefs(std::ofstream& stream);
   void GenInterfaceDef(std::ofstream& stream, const Interface& iface);
   void GenInterfaceContextDef(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionDefinition(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateDef(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
   void GenInterfaceCallbackPortCheckDef(std::ofstream& stream,
@@ -57,6 +59,8 @@ class CStubBodyGenerator : public CBodyGeneratorBase {
   void GenInterfaces(std::ofstream& stream);
   void GenInterface(std::ofstream& stream, const Interface& iface);
   void GenInterfaceContextBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionBase(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateBase(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
   void GenInterfaceMethodHandlerBase(std::ofstream& stream,
@@ -77,7 +81,8 @@ class CStubBodyGenerator : public CBodyGeneratorBase {
       const Declaration& decl);
   std::string GenMethodUnitMapRead(const Interface& iface,
       const Declaration& decl);
-  std::string GenMethodHandlerCallbackInvoke(const Declaration& decl);
+  std::string GenMethodHandlerCallbackInvoke(const Interface& iface,
+      const Declaration& decl);
   std::string GenMethodUnitMapWriteBase(
       const Interface& iface, const BaseType& type,
       const std::string& arg_name, const std::string& arg);
index 510419c..0fb434b 100644 (file)
@@ -1049,12 +1049,19 @@ rpc_port_parcel_read_<PARCEL_TYPE>(parcel, &<ARG>);
 )__c_cb";
 
 /**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
  * <RES_SET> The implemention to set the result of the callback function.
  * <METHOD_NAME> The name of the method of the interface.
  * <METHOD_ARGS> The arguments of the method.
  */
 constexpr const char CB_INTERFACE_METHOD_CALLBACK_INVOKE[] =
 R"__c_cb(
+if (__<PREFIX>_<NAME>_remote_exception != nullptr) {
+  <PREFIX>_<NAME>_remote_exception_destroy(__<PREFIX>_<NAME>_remote_exception);
+  __<PREFIX>_<NAME>_remote_exception = nullptr;
+}
+
 if (context_->callback.<METHOD_NAME>)
   <RES_SET>context_->callback.<METHOD_NAME>(context_<METHOD_ARGS>, context_->user_data);
 )__c_cb";
@@ -1086,8 +1093,14 @@ if (map_ == nullptr) {
 rpc_port_unit_map_write_int(map_, "[METHOD]",  <UPPERCASE_PREFIX>_<UPPERCASE_NAME>_METHOD_RESULT_);
 )__c_cb";
 
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
 constexpr const char CB_INTERFACE_METHOD_PARCEL_WRITE_POST[] =
 R"__c_cb(
+if (__<PREFIX>_<NAME>_remote_exception != nullptr)
+  rpc_port_unit_map_write_<NAME>_remote_exception(map_, "[REMOTE_EXCEPTION]", __<PREFIX>_<NAME>_remote_exception);
 
 rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
 rpc_port_unit_map_destroy(map_);
@@ -1428,4 +1441,165 @@ if (ret != RPC_PORT_ERROR_NONE) {
 }
 )__c_cb";
 
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_DEF[] =
+R"__c_cb(
+typedef struct <PREFIX>_<NAME>_remote_exception_s {
+  rpc_port_parcelable_t parcelable;
+  int cause;
+  char *message;
+} <PREFIX>_<NAME>_remote_exception_t;
+
+static __thread <PREFIX>_<NAME>_remote_exception_h __<PREFIX>_<NAME>_remote_exception;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] =
+R"__c_cb(
+static void __<PREFIX>_<NAME>_remote_exception_to(rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_remote_exception_h h = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_unit_map_write_int(map, "cause", h->cause);
+  rpc_port_unit_map_write_string(map, "message", h->message);
+  rpc_port_parcel_write(parcel, &map->parcelable, map);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void __<PREFIX>_<NAME>_remote_exception_from(rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_remote_exception_h h = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+  rpc_port_unit_map_read_int(map, "cause", &h->cause);
+  rpc_port_unit_map_read_string(map, "message", &h->message);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+int <PREFIX>_<NAME>_remote_exception_create(<PREFIX>_<NAME>_remote_exception_h *h)
+{
+  <PREFIX>_<NAME>_remote_exception_h exception;
+
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  exception = calloc(1, sizeof(<PREFIX>_<NAME>_remote_exception_t));
+  if (exception == nullptr) {
+    _E("calloc() is failed");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  exception->parcelable.to = __<PREFIX>_<NAME>_remote_exception_to;
+  exception->parcelable.from = __<PREFIX>_<NAME>_remote_exception_from;
+
+  *h = exception;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_set_cause(<PREFIX>_<NAME>_remote_exception_h h, int cause)
+{
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  h->cause = cause;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_set_message(<PREFIX>_<NAME>_remote_exception_h h, const char *message)
+{
+  if (h == nullptr || message == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (h->message)
+    free(h->message);
+
+  h->message = strdup(message);
+  if (h->message == nullptr) {
+    _E("strdup() is failed");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_remote_exception_throw(<PREFIX>_<NAME>_remote_exception_h h)
+{
+  rpc_port_unit_map_h map;
+  int ret;
+
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+   map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = rpc_port_unit_map_write_<NAME>_remote_exception(map, "clone", h);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to write remote exception. error(%d)", ret);
+    rpc_port_unit_map_destroy(map);
+    return ret;
+  }
+
+  if (__<PREFIX>_<NAME>_remote_exception != nullptr) {
+    <PREFIX>_<NAME>_remote_exception_destroy(__<PREFIX>_<NAME>_remote_exception);
+    __<PREFIX>_<NAME>_remote_exception = nullptr;
+  }
+
+  ret = rpc_port_unit_map_read_<NAME>_remote_exception(map, "clone", &__<PREFIX>_<NAME>_remote_exception);
+  rpc_port_unit_map_destroy(map);
+
+  return ret;
+}
+
+int <PREFIX>_<NAME>_remote_exception_destroy(<PREFIX>_<NAME>_remote_exception_h h)
+{
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (h->message)
+    free(h->message);
+
+  free(h);
+
+  return RPC_PORT_ERROR_NONE;
+}
+)__c_cb";
+
 #endif  // IDLC_C_GEN_C_STUB_BODY_GENERATOR_CB_H_
index 9cf7966..b912dd2 100644 (file)
@@ -50,6 +50,7 @@ void CStubHeaderGenerator::GenInterfaceHandles(std::ofstream& stream) {
 
     auto& iface = static_cast<const Interface&>(*b);
     GenInterfaceContextHandle(stream, iface);
+    GenInterfaceRemoteExceptionHandle(stream, iface);
     for (const auto& d : iface.GetDeclarations()) {
       if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
         continue;
@@ -70,6 +71,16 @@ void CStubHeaderGenerator::GenInterfaceContextHandle(std::ofstream& stream,
   stream << SmartIndent(code);
 }
 
+// @see #CB_INTERFACE_REMOTE_EXCEPTION_HANDLE
+void CStubHeaderGenerator::GenInterfaceRemoteExceptionHandle(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_HANDLE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 // @see #CB_INTERFACE_DELEGATE_HANDLE
 void CStubHeaderGenerator::GenInterfaceDelegateHandle(std::ofstream& stream,
     const Interface& iface, const Declaration& decl) {
@@ -150,6 +161,7 @@ void CStubHeaderGenerator::GenInterfaces(std::ofstream& stream) {
 void CStubHeaderGenerator::GenInterface(std::ofstream& stream,
     const Interface& iface) {
   GenInterfaceContextBase(stream, iface);
+  GenInterfaceRemoteExceptionBase(stream, iface);
   for (const auto& d : iface.GetDeclarations()) {
     if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
@@ -171,6 +183,16 @@ void CStubHeaderGenerator::GenInterfaceContextBase(std::ofstream& stream,
   stream << SmartIndent(code);
 }
 
+// @see #CB_INTERFACE_REMOTE_EXCEPTION_BASE
+void CStubHeaderGenerator::GenInterfaceRemoteExceptionBase(
+    std::ofstream& stream, const Interface& iface) {
+  ReplaceAll(CB_INTERFACE_REMOTE_EXCEPTION_BASE)
+      .Change("<PREFIX>", GetHandlePrefix())
+      .Change("<NAME>", iface.GetID())
+      .Transform([&](std::string code) { return SmartIndent(code); })
+      .Out(stream);
+}
+
 std::string CStubHeaderGenerator::GenDelegateParams(const Interface& iface,
     const Declaration& decl) {
   std::string params;
index edfd88c..e464947 100644 (file)
@@ -36,6 +36,8 @@ class CStubHeaderGenerator : public CHeaderGeneratorBase {
  private:
   void GenInterfaceHandles(std::ofstream& stream);
   void GenInterfaceContextHandle(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionHandle(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateHandle(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
 
@@ -48,6 +50,8 @@ class CStubHeaderGenerator : public CHeaderGeneratorBase {
   void GenInterface(std::ofstream& stream, const Interface& iface);
 
   void GenInterfaceContextBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceRemoteExceptionBase(std::ofstream& stream,
+      const Interface& iface);
   void GenInterfaceDelegateBase(std::ofstream& stream, const Interface& iface,
       const Declaration& decl);
   void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
@@ -61,4 +65,4 @@ class CStubHeaderGenerator : public CHeaderGeneratorBase {
 }  // namespace version2
 }  // namespace tidl
 
-#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_HH_
\ No newline at end of file
+#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_HH_
index 2258e7a..1893c52 100644 (file)
@@ -365,4 +365,91 @@ R"__c_cb(
 <PREFIX>_<NAME>_<METHOD_NAME>_cb <METHOD_NAME>;  /**< This callback function is invoked when the <METHOD_NAME> request is delivered. */
 )__c_cb";
 
-#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_
\ No newline at end of file
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_HANDLE[] =
+R"__c_cb(
+/**
+ * @brief The <PREFIX> <NAME> remote exception handle.
+ */
+typedef struct <PREFIX>_<NAME>_remote_exception_s *<PREFIX>_<NAME>_remote_exception_h;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] =
+R"__c_cb(
+/**
+ * @brief Creates the <PREFIX> <NAME> remote exception handle.
+ *
+ * @remarks The @c h handle should be released if it's no longer needed.
+ * @param[out] h The <PREFIX> <NAME> remote exception handle.
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @see <PREFIX>_<NAME>_remote_exception_throw()
+ * @see <PREFIX>_<NAME>_remote_exception_destroy()
+ */
+int <PREFIX>_<NAME>_remote_exception_create(<PREFIX>_<NAME>_remote_exception_h *h);
+
+/**
+ * @brief Sets the cause of the exception.
+ *
+ * @param[in] h The <PREFIX> <NAME> remote exception handle
+ * @param[in] cause The cause of the exception
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_remote_exception_set_cause(<PREFIX>_<NAME>_remote_exception_h h, int cause);
+
+/**
+ * @brief Sets the detail message of the exception.
+ *
+ * @param[in] h The <PREFIX> <NAME> remote exception handle
+ * @param[in] message The detail message of the exception
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_remote_exception_set_message(<PREFIX>_<NAME>_remote_exception_h h, const char *message);
+
+/**
+ * @brief Throws the exception to the client.
+ * @details This function throws the exception to the client in the callback function.
+ *          While calling the registered callback function related the method call, this function should be called
+ *          if you want to send the remote exception to the client.
+ *          If this function is called outside of the registered callback function, it's meaningless.
+ *          The callback function is not returned by calling this function.
+ *
+ * @param[in] h The <PREFIX> <NAME> remote exception handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_remote_exception_throw(<PREFIX>_<NAME>_remote_exception_h h);
+
+/**
+ * @brief Destroys the <PREFIX> <NAME> remote exception handle.
+ *
+ * @param[in] h The <PREFIX> <NAME> remote exception handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_remote_exception_destroy(<PREFIX>_<NAME>_remote_exception_h h);
+)__c_cb";
+
+#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_