From: Hwankyu Jhun Date: Tue, 14 Feb 2023 09:26:45 +0000 (+0000) Subject: Support sending exception feature X-Git-Tag: accepted/tizen/unified/20230420.153149~20 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F74%2F288274%2F9;p=platform%2Fcore%2Fappfw%2Ftidl.git Support sending exception feature 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 --- diff --git a/idlc/gen/version2/c_body_generator_base.cc b/idlc/gen/version2/c_body_generator_base.cc index 7fc0817..ce2d50d 100644 --- a/idlc/gen/version2/c_body_generator_base.cc +++ b/idlc/gen/version2/c_body_generator_base.cc @@ -1167,6 +1167,15 @@ void CBodyGeneratorBase::GenParameterMap() { for (auto& block : GetDocument().GetBlocks()) { if (block->GetType() == Block::TYPE_INTERFACE) { auto& iface = static_cast(*block); + AddParameterType( + std::make_shared( + new BaseType(iface.GetID() + "_remote_exception", "", true), + ParameterType::Direction::OUT)); + AddParameterType( + std::make_shared( + 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(); diff --git a/idlc/gen/version2/c_proxy_body_generator.cc b/idlc/gen/version2/c_proxy_body_generator.cc index 5fcb3ca..1731146 100644 --- a/idlc/gen/version2/c_proxy_body_generator.cc +++ b/idlc/gen/version2/c_proxy_body_generator.cc @@ -16,6 +16,8 @@ #include "idlc/gen/version2/c_proxy_body_generator.hh" +#include + #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("", GetHandlePrefix()) + .Change("", 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("", GetHandlePrefix()) + .Change("", 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("", 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("", GetHandlePrefix()) .Change("", GetFullNameFromType(type, iface)) .Change("", param->GetID()); + *has_free = true; } else if (type.ToString() == "bundle") { code += ReplaceAll(CB_INTERFACE_DELEGATE_BUNDLE_ARG_FREE, "", param->GetID()); + *has_free = true; } else if (type.ToString() == "string" || type.ToString() == "file") { code += ReplaceAll(CB_INTERFACE_DELEGATE_STRING_ARG_FREE, "", param->GetID()); + *has_free = true; } } diff --git a/idlc/gen/version2/c_proxy_body_generator.hh b/idlc/gen/version2/c_proxy_body_generator.hh index 5785f1f..29d0420 100644 --- a/idlc/gen/version2/c_proxy_body_generator.hh +++ b/idlc/gen/version2/c_proxy_body_generator.hh @@ -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); diff --git a/idlc/gen/version2/c_proxy_body_generator_cb.hh b/idlc/gen/version2/c_proxy_body_generator_cb.hh index a9c5a95..e968723 100644 --- a/idlc/gen/version2/c_proxy_body_generator_cb.hh +++ b/idlc/gen/version2/c_proxy_body_generator_cb.hh @@ -643,6 +643,12 @@ static void ____consume_command(rpc_port_h port, int seq_num, rpc_ rpc_port_unit_map_read_int(map, "[METHOD]", &cmd); if (cmd == __METHOD_RESULT_) { + if (____remote_exception != nullptr) + __remote_exception_destroy(____remote_exception); + + ____remote_exception = nullptr; + rpc_port_unit_map_read__remote_exception(map, "[REMOTE_EXCEPTION]", &____remote_exception); + *unit_map = map; return; } @@ -1178,6 +1184,167 @@ R"__c_cb( h->delegates = g_list_append(h->delegates, ); )__c_cb"; +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_DEF[] = +R"__c_cb( +typedef struct __remote_exception_s { + rpc_port_parcelable_t parcelable; + int cause; + char *message; +} __remote_exception_t; + +static __thread __remote_exception_h ____remote_exception; + +static int __remote_exception_create(__remote_exception_h *h); +)__c_cb"; + +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] = +R"__c_cb( +static void ____remote_exception_to(rpc_port_parcel_h parcel, void *user_data) +{ + __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 ____remote_exception_from(rpc_port_parcel_h parcel, void *user_data) +{ + __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 __remote_exception_create(__remote_exception_h *h) +{ + __remote_exception_h exception; + + if (h == nullptr) { + _E("Invalid parameter"); + return RPC_PORT_ERROR_INVALID_PARAMETER; + } + + exception = calloc(1, sizeof(__remote_exception_t)); + if (exception == nullptr) { + _E("calloc() is failed"); + return RPC_PORT_ERROR_OUT_OF_MEMORY; + } + + exception->parcelable.to = ____remote_exception_to; + exception->parcelable.from = ____remote_exception_from; + + *h = exception; + + return RPC_PORT_ERROR_NONE; +} + +int __get_remote_exception(__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 (____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__remote_exception(map, "clone", ____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__remote_exception(map, "clone", h); + rpc_port_unit_map_destroy(map); + + return RPC_PORT_ERROR_NONE; +} + +int __remote_exception_get_cause(__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 __remote_exception_get_message(__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 __remote_exception_destroy(__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 diff --git a/idlc/gen/version2/c_proxy_header_generator.cc b/idlc/gen/version2/c_proxy_header_generator.cc index 5faf706..8841359 100644 --- a/idlc/gen/version2/c_proxy_header_generator.cc +++ b/idlc/gen/version2/c_proxy_header_generator.cc @@ -48,6 +48,7 @@ void CProxyHeaderGenerator::GenInterfaceHandles(std::ofstream& stream) { auto& iface = static_cast(*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("", GetHandlePrefix()) + .Change("", 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("", GetHandlePrefix()) + .Change("", iface.GetID()) + .Transform([&](std::string code) { return SmartIndent(code); }) + .Out(stream); +} + std::string CProxyHeaderGenerator::GenDelegateParams(const Interface& iface, const Declaration& decl) { std::string params; diff --git a/idlc/gen/version2/c_proxy_header_generator.hh b/idlc/gen/version2/c_proxy_header_generator.hh index 9b69734..d7cb19f 100644 --- a/idlc/gen/version2/c_proxy_header_generator.hh +++ b/idlc/gen/version2/c_proxy_header_generator.hh @@ -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); diff --git a/idlc/gen/version2/c_proxy_header_generator_cb.hh b/idlc/gen/version2/c_proxy_header_generator_cb.hh index a7e66ea..ceec0ff 100644 --- a/idlc/gen/version2/c_proxy_header_generator_cb.hh +++ b/idlc/gen/version2/c_proxy_header_generator_cb.hh @@ -340,6 +340,65 @@ R"__c_cb( __invoke_(__h h); )__c_cb"; +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_HANDLE[] = +R"__c_cb( +/** + * @breif The remote exception handle. + */ +typedef struct __remote_exception_s *__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 __remote_exception_destroy(), if it's no longer needed. + * @param[out] h The 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 __remote_exception_destroy(); + */ +int __get_remote_exception(__remote_exception_h *h); + +/** + * @brief Gets the cause of the exception. + * @param[in] h The 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 __remote_exception_get_cause(__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 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 __remote_exception_get_message(__remote_exception_h, char **message); + +/** + * @brief Destroys the remote exception handle. + * @param[in] h The 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 __remote_exception_destroy(__remote_exception_h h); +)__c_cb"; + } // namespace version2 } // namespace tidl diff --git a/idlc/gen/version2/c_stub_body_generator.cc b/idlc/gen/version2/c_stub_body_generator.cc index ca08baf..adb29f8 100644 --- a/idlc/gen/version2/c_stub_body_generator.cc +++ b/idlc/gen/version2/c_stub_body_generator.cc @@ -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("", GetHandlePrefix()) + .Change("", 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("", GetHandlePrefix()) + .Change("", 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, "", decl.GetID())); + code = ReplaceAll(code, "", GetHandlePrefix()); + code = ReplaceAll(code, "", iface.GetID()); if (decl.GetMethodType() == Declaration::MethodType::SYNC) code = ReplaceAll(code, "", "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("", GetHandlePrefix()) + .Change("", iface.GetID()); return RemoveLine(code); } @@ -621,7 +647,7 @@ void CStubBodyGenerator::GenInterfaceMethodHandlerBase(std::ofstream& stream, { "", GenMethodUnitMapRead(iface, decl) }, { "", - GenMethodHandlerCallbackInvoke(decl) }, + GenMethodHandlerCallbackInvoke(iface, decl) }, { "", GenMethodUnitMapWrite(iface, decl) }, { "", GenMethodHandlerArgsFree(iface, decl) } diff --git a/idlc/gen/version2/c_stub_body_generator.hh b/idlc/gen/version2/c_stub_body_generator.hh index 639f476..90b73ba 100644 --- a/idlc/gen/version2/c_stub_body_generator.hh +++ b/idlc/gen/version2/c_stub_body_generator.hh @@ -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); diff --git a/idlc/gen/version2/c_stub_body_generator_cb.hh b/idlc/gen/version2/c_stub_body_generator_cb.hh index 510419c..0fb434b 100644 --- a/idlc/gen/version2/c_stub_body_generator_cb.hh +++ b/idlc/gen/version2/c_stub_body_generator_cb.hh @@ -1049,12 +1049,19 @@ rpc_port_parcel_read_(parcel, &); )__c_cb"; /** + * The prefix of the interface. + * The name of the interface. * The implemention to set the result of the callback function. * The name of the method of the interface. * The arguments of the method. */ constexpr const char CB_INTERFACE_METHOD_CALLBACK_INVOKE[] = R"__c_cb( +if (____remote_exception != nullptr) { + __remote_exception_destroy(____remote_exception); + ____remote_exception = nullptr; +} + if (context_->callback.) context_->callback.(context_, context_->user_data); )__c_cb"; @@ -1086,8 +1093,14 @@ if (map_ == nullptr) { rpc_port_unit_map_write_int(map_, "[METHOD]", __METHOD_RESULT_); )__c_cb"; +/** + * The prefix of the interface. + * The name of the interface. + */ constexpr const char CB_INTERFACE_METHOD_PARCEL_WRITE_POST[] = R"__c_cb( +if (____remote_exception != nullptr) + rpc_port_unit_map_write__remote_exception(map_, "[REMOTE_EXCEPTION]", ____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"; +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_DEF[] = +R"__c_cb( +typedef struct __remote_exception_s { + rpc_port_parcelable_t parcelable; + int cause; + char *message; +} __remote_exception_t; + +static __thread __remote_exception_h ____remote_exception; +)__c_cb"; + +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] = +R"__c_cb( +static void ____remote_exception_to(rpc_port_parcel_h parcel, void *user_data) +{ + __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 ____remote_exception_from(rpc_port_parcel_h parcel, void *user_data) +{ + __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 __remote_exception_create(__remote_exception_h *h) +{ + __remote_exception_h exception; + + if (h == nullptr) { + _E("Invalid parameter"); + return RPC_PORT_ERROR_INVALID_PARAMETER; + } + + exception = calloc(1, sizeof(__remote_exception_t)); + if (exception == nullptr) { + _E("calloc() is failed"); + return RPC_PORT_ERROR_OUT_OF_MEMORY; + } + + exception->parcelable.to = ____remote_exception_to; + exception->parcelable.from = ____remote_exception_from; + + *h = exception; + + return RPC_PORT_ERROR_NONE; +} + +int __remote_exception_set_cause(__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 __remote_exception_set_message(__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 __remote_exception_throw(__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__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 (____remote_exception != nullptr) { + __remote_exception_destroy(____remote_exception); + ____remote_exception = nullptr; + } + + ret = rpc_port_unit_map_read__remote_exception(map, "clone", &____remote_exception); + rpc_port_unit_map_destroy(map); + + return ret; +} + +int __remote_exception_destroy(__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_ diff --git a/idlc/gen/version2/c_stub_header_generator.cc b/idlc/gen/version2/c_stub_header_generator.cc index 9cf7966..b912dd2 100644 --- a/idlc/gen/version2/c_stub_header_generator.cc +++ b/idlc/gen/version2/c_stub_header_generator.cc @@ -50,6 +50,7 @@ void CStubHeaderGenerator::GenInterfaceHandles(std::ofstream& stream) { auto& iface = static_cast(*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("", GetHandlePrefix()) + .Change("", 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("", GetHandlePrefix()) + .Change("", iface.GetID()) + .Transform([&](std::string code) { return SmartIndent(code); }) + .Out(stream); +} + std::string CStubHeaderGenerator::GenDelegateParams(const Interface& iface, const Declaration& decl) { std::string params; diff --git a/idlc/gen/version2/c_stub_header_generator.hh b/idlc/gen/version2/c_stub_header_generator.hh index edfd88c..e464947 100644 --- a/idlc/gen/version2/c_stub_header_generator.hh +++ b/idlc/gen/version2/c_stub_header_generator.hh @@ -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_ diff --git a/idlc/gen/version2/c_stub_header_generator_cb.hh b/idlc/gen/version2/c_stub_header_generator_cb.hh index 2258e7a..1893c52 100644 --- a/idlc/gen/version2/c_stub_header_generator_cb.hh +++ b/idlc/gen/version2/c_stub_header_generator_cb.hh @@ -365,4 +365,91 @@ R"__c_cb( ___cb ; /**< This callback function is invoked when the request is delivered. */ )__c_cb"; -#endif // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_ \ No newline at end of file +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_HANDLE[] = +R"__c_cb( +/** + * @brief The remote exception handle. + */ +typedef struct __remote_exception_s *__remote_exception_h; +)__c_cb"; + +/** + * The prefix of the interface. + * The name of the interface. + */ +constexpr const char CB_INTERFACE_REMOTE_EXCEPTION_BASE[] = +R"__c_cb( +/** + * @brief Creates the remote exception handle. + * + * @remarks The @c h handle should be released if it's no longer needed. + * @param[out] h The 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 __remote_exception_throw() + * @see __remote_exception_destroy() + */ +int __remote_exception_create(__remote_exception_h *h); + +/** + * @brief Sets the cause of the exception. + * + * @param[in] h The 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 __remote_exception_set_cause(__remote_exception_h h, int cause); + +/** + * @brief Sets the detail message of the exception. + * + * @param[in] h The 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 __remote_exception_set_message(__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 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 __remote_exception_throw(__remote_exception_h h); + +/** + * @brief Destroys the remote exception handle. + * + * @param[in] h The 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 __remote_exception_destroy(__remote_exception_h h); +)__c_cb"; + +#endif // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_