diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt b/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt index f3931c74b..aa33865f8 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt @@ -57,6 +57,8 @@ get_property(remote_example_bundle_file TARGET remote_example_service PROPERTY B configure_file(config.properties.in config.properties) configure_file(client.properties.in client.properties) configure_file(server.properties.in server.properties) +#add exception service interface descriptor +configure_file(exception_test_service.descriptor exception_test_service.descriptor) add_dependencies(test_rsa_dfi rsa_dfi_bundle #note depend on the target creating the bundle zip not the lib target diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/exception_test_service.descriptor b/bundles/remote_services/remote_service_admin_dfi/gtest/exception_test_service.descriptor new file mode 100644 index 000000000..957e05ffc --- /dev/null +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/exception_test_service.descriptor @@ -0,0 +1,9 @@ +:header +type=interface +name=exception_test +version=1.0.0 +:annotations +classname=exception_test_service +:types +:methods +func1(V)V=func1(#am=handle;P)N diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc index a47e3ed29..5afd956e3 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc @@ -34,6 +34,13 @@ extern "C" { #include "celix_launcher.h" #include "framework.h" #include "remote_service_admin.h" +#include "remote_interceptor.h" + +#define RSA_DIF_EXCEPTION_TEST_SERVICE "exception_test_service" +typedef struct rsa_dfi_exception_test_service { + void *handle; + int (*func1)(void *handle); +}rsa_dfi_exception_test_service_t; static celix_framework_t *serverFramework = NULL; static celix_bundle_context_t *serverContext = NULL; @@ -41,6 +48,15 @@ extern "C" { static celix_framework_t *clientFramework = NULL; static celix_bundle_context_t *clientContext = NULL; + static rsa_dfi_exception_test_service_t *exceptionTestService = NULL; + static long exceptionTestSvcId = -1L; + static remote_interceptor_t *serverSvcInterceptor=NULL; + static remote_interceptor_t *clientSvcInterceptor=NULL; + static long serverSvcInterceptorSvcId = -1L; + static long clientSvcInterceptorSvcId = -1L; + static bool clientInterceptorPreProxyCallRetval=true; + static bool svcInterceptorPreExportCallRetval=true; + static void setupFm(bool useCurlShare) { //server celix_properties_t *serverProps = celix_properties_load("server.properties"); @@ -65,6 +81,99 @@ extern "C" { celix_frameworkFactory_destroyFramework(clientFramework); } + static int rsaDfi_excepTestFunc1(void *handle __attribute__((unused))) { + return CELIX_CUSTOMER_ERROR_MAKE(0,1); + } + + static void registerExceptionTestServer(void) { + celix_properties_t *properties = celix_properties_create(); + celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_DIF_EXCEPTION_TEST_SERVICE); + celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, "org.amdatu.remote.admin.http"); + exceptionTestService = (rsa_dfi_exception_test_service_t *)calloc(1,sizeof(*exceptionTestService)); + exceptionTestService->handle = NULL; + exceptionTestService->func1 = rsaDfi_excepTestFunc1; + exceptionTestSvcId = celix_bundleContext_registerService(serverContext, exceptionTestService, RSA_DIF_EXCEPTION_TEST_SERVICE, properties); + } + + static void unregisterExceptionTestServer(void) { + celix_bundleContext_unregisterService(serverContext, exceptionTestSvcId); + free(exceptionTestService); + } + + static bool serverServiceInterceptor_preProxyCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + return true; + } + + static void serverServiceInterceptor_postProxyCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + + } + + static bool serverServiceInterceptor_preExportCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + return svcInterceptorPreExportCallRetval; + } + + static void serverServiceInterceptor_postExportCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + + } + + static bool clientServiceInterceptor_preProxyCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + return clientInterceptorPreProxyCallRetval; + } + + static void clientServiceInterceptor_postProxyCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + + } + + static bool clientServiceInterceptor_preExportCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + return true; + } + + static void clientServiceInterceptor_postExportCall(void *, const celix_properties_t *, const char *, celix_properties_t *) { + + } + + static void registerInterceptorService(void) { + svcInterceptorPreExportCallRetval = true; + serverSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*serverSvcInterceptor)); + serverSvcInterceptor->handle = NULL; + serverSvcInterceptor->preProxyCall = serverServiceInterceptor_preProxyCall; + serverSvcInterceptor->postProxyCall = serverServiceInterceptor_postProxyCall; + serverSvcInterceptor->preExportCall = serverServiceInterceptor_preExportCall; + serverSvcInterceptor->postExportCall = serverServiceInterceptor_postExportCall; + celix_properties_t *svcInterceptorProps = celix_properties_create(); + celix_properties_setLong(svcInterceptorProps, OSGI_FRAMEWORK_SERVICE_RANKING, 10); + celix_service_registration_options_t svcInterceptorOpts{}; + svcInterceptorOpts.svc = serverSvcInterceptor; + svcInterceptorOpts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; + svcInterceptorOpts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + svcInterceptorOpts.properties = svcInterceptorProps; + serverSvcInterceptorSvcId = celix_bundleContext_registerServiceWithOptions(serverContext, &svcInterceptorOpts); + + clientInterceptorPreProxyCallRetval = true; + clientSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*clientSvcInterceptor)); + clientSvcInterceptor->handle = NULL; + clientSvcInterceptor->preProxyCall = clientServiceInterceptor_preProxyCall; + clientSvcInterceptor->postProxyCall = clientServiceInterceptor_postProxyCall; + clientSvcInterceptor->preExportCall = clientServiceInterceptor_preExportCall; + clientSvcInterceptor->postExportCall = clientServiceInterceptor_postExportCall; + celix_properties_t *clientInterceptorProps = celix_properties_create(); + celix_properties_setLong(clientInterceptorProps, OSGI_FRAMEWORK_SERVICE_RANKING, 10); + celix_service_registration_options_t clientInterceptorOpts{}; + clientInterceptorOpts.svc = clientSvcInterceptor; + clientInterceptorOpts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; + clientInterceptorOpts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + clientInterceptorOpts.properties = clientInterceptorProps; + clientSvcInterceptorSvcId = celix_bundleContext_registerServiceWithOptions(clientContext, &clientInterceptorOpts); + } + + static void unregisterInterceptorService(void) { + celix_bundleContext_unregisterService(clientContext, clientSvcInterceptorSvcId); + free(clientSvcInterceptor); + + celix_bundleContext_unregisterService(serverContext, serverSvcInterceptorSvcId); + free(serverSvcInterceptor); + } + static void testComplex(void *handle __attribute__((unused)), void *svc) { auto *tst = static_cast(svc); @@ -149,6 +258,37 @@ extern "C" { ASSERT_TRUE(ok); }; + static void testInterceptorPreExportCallReturnFalse(void *handle __attribute__((unused)), void *svc) { + svcInterceptorPreExportCallRetval = false; + auto *tst = static_cast(svc); + + bool ok = tst->testRemoteAction(tst->handle); + ASSERT_FALSE(ok); + } + + static void testInterceptorPreProxyCallReturnFalse(void *handle __attribute__((unused)), void *svc) { + clientInterceptorPreProxyCallRetval = false; + auto *tst = static_cast(svc); + + bool ok = tst->testRemoteAction(tst->handle); + ASSERT_FALSE(ok); + } + + static void testExceptionServiceCallback(void *handle __attribute__((unused)), void *svc) { + rsa_dfi_exception_test_service_t * service = (rsa_dfi_exception_test_service_t *)(svc); + int ret = service->func1(service->handle); + EXPECT_EQ(CELIX_CUSTOMER_ERROR_MAKE(0,1),ret); + } + + static void testExceptionService(void) { + celix_service_use_options_t opts{}; + opts.filter.serviceName = RSA_DIF_EXCEPTION_TEST_SERVICE; + opts.use = testExceptionServiceCallback; + opts.filter.ignoreServiceLanguage = true; + opts.waitTimeoutInSeconds = 2; + bool called = celix_bundleContext_useServiceWithOptions(clientContext, &opts); + ASSERT_TRUE(called); + } } template @@ -184,6 +324,29 @@ class RsaDfiClientServerWithCurlShareTests : public ::testing::Test { }; +class RsaDfiClientServerInterceptorTests : public ::testing::Test { +public: + RsaDfiClientServerInterceptorTests() { + setupFm(false); + registerInterceptorService(); + } + ~RsaDfiClientServerInterceptorTests() override { + unregisterInterceptorService(); + teardownFm(); + } +}; + +class RsaDfiClientServerExceptionTests : public ::testing::Test { +public: + RsaDfiClientServerExceptionTests() { + setupFm(false); + registerExceptionTestServer(); + } + ~RsaDfiClientServerExceptionTests() override { + unregisterExceptionTestServer(); + teardownFm(); + } +}; TEST_F(RsaDfiClientServerTests, TestRemoteCalculator) { test(testCalculator); @@ -228,3 +391,15 @@ TEST_F(RsaDfiClientServerTests, CreateDestroyComponentWithRemoteService) { TEST_F(RsaDfiClientServerTests, AddRemoteServiceInRemoteService) { test(testAddRemoteServiceInRemoteService); } + +TEST_F(RsaDfiClientServerInterceptorTests,TestInterceptorPreExportCallReturnFalse) { + test(testInterceptorPreExportCallReturnFalse); +} + +TEST_F(RsaDfiClientServerInterceptorTests,TestInterceptorPreProxyCallReturnFalse) { + test(testInterceptorPreProxyCallReturnFalse); +} + +TEST_F(RsaDfiClientServerExceptionTests,TestExceptionService) { + testExceptionService(); +} diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c index f8a9e2142..031731f6d 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c @@ -369,4 +369,4 @@ static celix_status_t bndStop(struct activator *act, celix_bundle_context_t* ctx return CELIX_SUCCESS; } -CELIX_GEN_BUNDLE_ACTIVATOR(struct activator, bndStart, bndStop); \ No newline at end of file +CELIX_GEN_BUNDLE_ACTIVATOR(struct activator, bndStart, bndStop); diff --git a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c index 7af2cd953..770ec59fd 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c @@ -154,7 +154,7 @@ void exportRegistration_waitTillNotUsed(export_registration_t *export) { celixThreadMutex_unlock(&export->mutex); } -celix_status_t exportRegistration_call(export_registration_t *export, char *data, int datalength, celix_properties_t *metadata, char **responseOut, int *responseLength) { +celix_status_t exportRegistration_call(export_registration_t *export, char *data, int datalength, celix_properties_t **metadata, char **responseOut, int *responseLength) { int status = CELIX_SUCCESS; char* response = NULL; @@ -164,11 +164,12 @@ celix_status_t exportRegistration_call(export_registration_t *export, char *data const char *sig; if (js_request) { if (json_unpack(js_request, "{s:s}", "m", &sig) == 0) { - bool cont = remoteInterceptorHandler_invokePreExportCall(export->interceptorsHandler, export->exportReference.endpoint->properties, sig, &metadata); + bool cont = remoteInterceptorHandler_invokePreExportCall(export->interceptorsHandler, export->exportReference.endpoint->properties, sig, metadata); if (cont) { celixThreadMutex_lock(&export->mutex); if (export->active && export->service != NULL) { - status = jsonRpc_call(export->intf, export->service, data, &response); + int rc = jsonRpc_call(export->intf, export->service, data, &response); + status = (rc != 0) ? CELIX_BUNDLE_EXCEPTION : CELIX_SUCCESS; } else if (!export->active) { status = CELIX_ILLEGAL_STATE; celix_logHelper_warning(export->helper, "Cannot call an inactive service export"); @@ -178,7 +179,7 @@ celix_status_t exportRegistration_call(export_registration_t *export, char *data } celixThreadMutex_unlock(&export->mutex); - remoteInterceptorHandler_invokePostExportCall(export->interceptorsHandler, export->exportReference.endpoint->properties, sig, metadata); + remoteInterceptorHandler_invokePostExportCall(export->interceptorsHandler, export->exportReference.endpoint->properties, sig, *metadata); } *responseOut = response; diff --git a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.h b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.h index b07b8699d..37809df74 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.h +++ b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.h @@ -31,7 +31,7 @@ void exportRegistration_destroy(export_registration_t *registration); celix_status_t exportRegistration_start(export_registration_t *registration); void exportRegistration_setActive(export_registration_t *registration, bool active); -celix_status_t exportRegistration_call(export_registration_t *export, char *data, int datalength, celix_properties_t *metadata, char **response, int *responseLength); +celix_status_t exportRegistration_call(export_registration_t *export, char *data, int datalength, celix_properties_t **metadata, char **response, int *responseLength); void exportRegistration_increaseUsage(export_registration_t *export); void exportRegistration_decreaseUsage(export_registration_t *export); diff --git a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c index 70221c24b..e10997e6e 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c @@ -315,6 +315,8 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret struct method_entry *entry = userData; import_registration_t *import = *((void **)args[0]); + *(int *) returnVal = CELIX_SUCCESS; + if (import == NULL || import->send == NULL) { status = CELIX_ILLEGAL_ARGUMENT; } @@ -322,7 +324,8 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret char *invokeRequest = NULL; if (status == CELIX_SUCCESS) { - status = jsonRpc_prepareInvokeRequest(entry->dynFunc, entry->id, args, &invokeRequest); + int rc = jsonRpc_prepareInvokeRequest(entry->dynFunc, entry->id, args, &invokeRequest); + status = (rc != 0) ? CELIX_BUNDLE_EXCEPTION : CELIX_SUCCESS; //printf("Need to send following json '%s'\n", invokeRequest); } @@ -334,17 +337,31 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret celix_properties_t *metadata = NULL; bool cont = remoteInterceptorHandler_invokePreProxyCall(import->interceptorsHandler, import->endpoint->properties, entry->name, &metadata); if (cont) { - import->send(import->sendHandle, import->endpoint, invokeRequest, metadata, &reply, &rc); + status = import->send(import->sendHandle, import->endpoint, invokeRequest, metadata, &reply, &rc); //printf("request sended. got reply '%s' with status %i\n", reply, rc); - if (rc == 0 && dynFunction_hasReturn(entry->dynFunc)) { + if (status == CELIX_SUCCESS && rc == CELIX_SUCCESS && dynFunction_hasReturn(entry->dynFunc)) { //fjprintf("Handling reply '%s'\n", reply); - status = jsonRpc_handleReply(entry->dynFunc, reply, args); + int rsErrno = CELIX_SUCCESS; + int retVal = jsonRpc_handleReply(entry->dynFunc, reply, args, &rsErrno); + if(retVal != 0) { + status = CELIX_BUNDLE_EXCEPTION; + } else if (rsErrno != CELIX_SUCCESS) { + //return the invocation error of remote service function + *(int *) returnVal = rsErrno; + } + } else if (rc != CELIX_SUCCESS) { + *(int *) returnVal = rc; } - *(int *) returnVal = rc; - remoteInterceptorHandler_invokePostProxyCall(import->interceptorsHandler, import->endpoint->properties, entry->name, metadata); + } else { + *(int *) returnVal = CELIX_INTERCEPTOR_EXCEPTION; + } + + //free metadata + if(metadata != NULL) { + celix_properties_destroy(metadata); } if (import->logFile != NULL) { @@ -362,6 +379,7 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret if (status != CELIX_SUCCESS) { //TODO log error + *(int *) returnVal = status; } } diff --git a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h index 75d40bb8f..13353204f 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h +++ b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h @@ -25,7 +25,7 @@ #include -typedef void (*send_func_type)(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply, int* replyStatus); +typedef celix_status_t (*send_func_type)(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply, int* replyStatus); celix_status_t importRegistration_create( celix_bundle_context_t *context, diff --git a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c index ced1a0802..97dfb001c 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c @@ -501,7 +501,7 @@ static int remoteServiceAdmin_callback(struct mg_connection *conn) { char *response = NULL; int responceLength = 0; - int rc = exportRegistration_call(export, data, -1, metadata, &response, &responceLength); + int rc = exportRegistration_call(export, data, -1, &metadata, &response, &responceLength); if (rc != CELIX_SUCCESS) { RSA_LOG_ERROR(rsa, "Error trying to invoke remove service, got error %i\n", rc); } @@ -534,11 +534,14 @@ static int remoteServiceAdmin_callback(struct mg_connection *conn) { free(data); exportRegistration_decreaseUsage(export); - - //TODO free metadata? } } + //free metadata + if(metadata != NULL) { + celix_properties_destroy(metadata); + } + return result; } @@ -957,7 +960,7 @@ static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description fputc('\0', get.stream); fclose(get.stream); *reply = get.buf; - *replyStatus = res; + *replyStatus = (res == CURLE_OK) ? CELIX_SUCCESS:CELIX_ERROR_MAKE(CELIX_FACILITY_HTTP,res); curl_easy_cleanup(curl); curl_slist_free_all(metadataHeader); diff --git a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c index c1f830f50..c8bb1e75a 100644 --- a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c +++ b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c @@ -117,6 +117,7 @@ void remoteInterceptorsHandler_removeInterceptor(void *handle, void *svc, __attr entry_t *entry = arrayList_get(handler->interceptors, i); if (entry->interceptor == svc) { arrayList_remove(handler->interceptors, i); + free(entry); break; } } @@ -205,4 +206,4 @@ int referenceCompare(const void *a, const void *b) { long servRankingB = celix_properties_getAsLong(bEntry->properties, OSGI_FRAMEWORK_SERVICE_RANKING, 0); return celix_utils_compareServiceIdsAndRanking(servIdA, servRankingA, servIdB, servRankingB); -} \ No newline at end of file +} diff --git a/libs/dfi/gtest/src/json_rpc_avpr_tests.cpp b/libs/dfi/gtest/src/json_rpc_avpr_tests.cpp index b302deec9..fb9c66b42 100644 --- a/libs/dfi/gtest/src/json_rpc_avpr_tests.cpp +++ b/libs/dfi/gtest/src/json_rpc_avpr_tests.cpp @@ -201,8 +201,10 @@ TEST_F(JsonAvprRpcTests, prep) { //double **out_ptr = &out; args[3] = &out; - rc = jsonRpc_handleReply(func, reply, args); + int rsErrno = 0; + rc = jsonRpc_handleReply(func, reply, args, &rsErrno); ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); ASSERT_NEAR(2.2, calc_result, 0.001); free(result); @@ -255,8 +257,10 @@ TEST_F(JsonAvprRpcTests, handle_out) { void *out = &result; args[2] = &out; - int rc = jsonRpc_handleReply(func, reply, args); + int rsErrno = 0; + int rc = jsonRpc_handleReply(func, reply, args, &rsErrno); ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); ASSERT_TRUE(result != nullptr); ASSERT_EQ(1.5, result->average); diff --git a/libs/dfi/gtest/src/json_rpc_tests.cpp b/libs/dfi/gtest/src/json_rpc_tests.cpp index 8f8d744d8..cc57b8faf 100644 --- a/libs/dfi/gtest/src/json_rpc_tests.cpp +++ b/libs/dfi/gtest/src/json_rpc_tests.cpp @@ -35,6 +35,7 @@ extern "C" { #include "dyn_type.h" #include "json_serializer.h" #include "json_rpc.h" +#include "celix_errno.h" static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) { va_list ap; @@ -86,8 +87,10 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg double *out = &result; void *args[4]; args[3] = &out; - rc = jsonRpc_handleReply(dynFunc, reply, args); + int rsErrno = 0; + rc = jsonRpc_handleReply(dynFunc, reply, args, &rsErrno); ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); //ASSERT_EQ(2.2, result); dynFunction_destroy(dynFunc); @@ -98,6 +101,10 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg return 0; } + int addFailed(void*, double , double , double *) { + return CELIX_CUSTOMER_ERROR_MAKE(0,1);// return customer error + } + int getName_example4(void*, char** result) { *result = strdup("allocatedInFunction"); return 0; @@ -198,6 +205,25 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg dynInterface_destroy(intf); } + void callFailedTestPreAllocated(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example1.descriptor", "r"); + ASSERT_TRUE(desc != nullptr); + int rc = dynInterface_parse(desc, &intf); + ASSERT_EQ(0, rc); + fclose(desc); + + char *result = nullptr; + tst_serv serv {nullptr, addFailed, nullptr, nullptr, nullptr}; + + rc = jsonRpc_call(intf, &serv, R"({"m":"add(DD)D", "a": [1.0,2.0]})", &result); + ASSERT_EQ(0, rc); + ASSERT_TRUE(strstr(result, "e") != nullptr); + + free(result); + dynInterface_destroy(intf); + } + void callTestOutput(void) { dyn_interface_type *intf = nullptr; FILE *desc = fopen("descriptors/example1.descriptor", "r"); @@ -248,8 +274,10 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg void *out = &result; args[2] = &out; - rc = jsonRpc_handleReply(func, reply, args); + int rsErrno = 0; + rc = jsonRpc_handleReply(func, reply, args, &rsErrno); ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); ASSERT_EQ(1.5, result->average); free(result->input.buf); @@ -257,6 +285,47 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg dynInterface_destroy(intf); } + void handleTestReplyError(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example1.descriptor", "r"); + ASSERT_TRUE(desc != nullptr); + int rc = dynInterface_parse(desc, &intf); + ASSERT_EQ(0, rc); + fclose(desc); + + struct methods_head *head; + dynInterface_methods(intf, &head); + dyn_function_type *func = nullptr; + struct method_entry *entry = nullptr; + TAILQ_FOREACH(entry, head, entries) { + if (strcmp(entry->name, "add") == 0) { + func = entry->dynFunc; + break; + } + } + ASSERT_TRUE(func != nullptr); + + const char *reply = R"({"e":33554433})"; + + void *args[4]; + args[0] = nullptr; + args[1] = nullptr; + args[2] = nullptr; + args[3] = nullptr; + + double result = 0; + void *out = &result; + args[3] = &out; + + int rsErrno = 0; + rc = jsonRpc_handleReply(func, reply, args, &rsErrno); + ASSERT_EQ(0, rc); + ASSERT_EQ(33554433, rsErrno); + ASSERT_EQ(0, result); + + dynInterface_destroy(intf); + } + static void handleTestOutputSequence() { dyn_interface_type *intf = nullptr; FILE *desc = fopen("descriptors/example2.descriptor", "r"); @@ -290,8 +359,10 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg void *out = &result; args[1] = &out; - rc = jsonRpc_handleReply(func, reply, args); + int rsErrno = 0; + rc = jsonRpc_handleReply(func, reply, args, &rsErrno); ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); ASSERT_EQ(2, result->len); ASSERT_EQ(1.0, result->buf[0]->a); ASSERT_EQ(1.5, result->buf[0]->b); @@ -362,7 +433,9 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg args[1] = &out; if (func != nullptr) { // Check needed just to satisfy Coverity - jsonRpc_handleReply(func, reply, args); + int rsErrno = 0; + jsonRpc_handleReply(func, reply, args, &rsErrno); + ASSERT_EQ(0, rsErrno); } ASSERT_STREQ("this is a test string", result); @@ -404,6 +477,10 @@ TEST_F(JsonRpcTests, callPre) { callTestPreAllocated(); } +TEST_F(JsonRpcTests, callFailedPre) { + callFailedTestPreAllocated(); +} + TEST_F(JsonRpcTests, callOut) { callTestOutput(); } @@ -420,3 +497,6 @@ TEST_F(JsonRpcTests, handleOutChar) { handleTestOutChar(); } +TEST_F(JsonRpcTests, handleReplyError) { + handleTestReplyError(); +} diff --git a/libs/dfi/include/json_rpc.h b/libs/dfi/include/json_rpc.h index f2a729157..363d051e7 100644 --- a/libs/dfi/include/json_rpc.h +++ b/libs/dfi/include/json_rpc.h @@ -37,7 +37,7 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void *args[], char **out); -int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[]); +int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[], int *rsErrno); #ifdef __cplusplus } diff --git a/libs/dfi/src/json_rpc.c b/libs/dfi/src/json_rpc.c index edd9aa7a7..7203a43e5 100644 --- a/libs/dfi/src/json_rpc.c +++ b/libs/dfi/src/json_rpc.c @@ -177,52 +177,50 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c } //serialize and free output - if (funcCallStatus == 0 && status == OK) { - for (i = 0; i < nrOfArgs; i += 1) { - dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); - enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); - if (meta == DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT) { + for (i = 0; i < nrOfArgs; i += 1) { + dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); + enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); + if (meta == DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT) { + if (funcCallStatus == 0 && status == OK) { + status = jsonSerializer_serializeJson(argType, args[i], &jsonResult); + } + dyn_type *subType = NULL; + dynType_typedPointer_getTypedType(argType, &subType); + void **ptrToInst = (void**)args[i]; + dynType_free(subType, *ptrToInst); + free(ptrToInst); + } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { + if (funcCallStatus == 0 && ptr != NULL) { + dyn_type *typedType = NULL; if (status == OK) { - status = jsonSerializer_serializeJson(argType, args[i], &jsonResult); + status = dynType_typedPointer_getTypedType(argType, &typedType); } - dyn_type *subType = NULL; - dynType_typedPointer_getTypedType(argType, &subType); - void **ptrToInst = (void**)args[i]; - dynType_free(subType, *ptrToInst); - free(ptrToInst); - } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { - if (ptr != NULL) { - dyn_type *typedType = NULL; + if (status == OK && dynType_descriptorType(typedType) == 't') { + status = jsonSerializer_serializeJson(typedType, (void*) &ptr, &jsonResult); + free(ptr); + } else { + dyn_type *typedTypedType = NULL; if (status == OK) { - status = dynType_typedPointer_getTypedType(argType, &typedType); + status = dynType_typedPointer_getTypedType(typedType, &typedTypedType); } - if (dynType_descriptorType(typedType) == 't') { - status = jsonSerializer_serializeJson(typedType, (void*) &ptr, &jsonResult); - free(ptr); - } else { - dyn_type *typedTypedType = NULL; - if (status == OK) { - status = dynType_typedPointer_getTypedType(typedType, &typedTypedType); - } - - if(status == OK){ - status = jsonSerializer_serializeJson(typedTypedType, ptr, &jsonResult); - } - - if (status == OK) { - dynType_free(typedTypedType, ptr); - } + + if(status == OK){ + status = jsonSerializer_serializeJson(typedTypedType, ptr, &jsonResult); } - } else { - LOG_DEBUG("Output ptr is null"); + if (status == OK) { + dynType_free(typedTypedType, ptr); + } } - } - if (status != OK) { - break; + } else { + LOG_DEBUG("Output ptr is null"); } } + + if (status != OK) { + break; + } } char *response = NULL; @@ -306,7 +304,7 @@ int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void * return status; } -int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[]) { +int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[], int *rsErrno) { int status = OK; json_error_t error; @@ -317,11 +315,19 @@ int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[] } json_t *result = NULL; + json_t *rsError = NULL; bool replyHasResult = false; if (status == OK) { + *rsErrno = 0; result = json_object_get(replyJson, "r"); if (result != NULL) { replyHasResult = true; + } else { + rsError = json_object_get(replyJson, "e"); + if(rsError != NULL) { + //get the invocation error of remote service function + *rsErrno = json_integer_value(rsError); + } } } diff --git a/libs/utils/include/celix_errno.h b/libs/utils/include/celix_errno.h index 731af8288..a1e76a1fe 100644 --- a/libs/utils/include/celix_errno.h +++ b/libs/utils/include/celix_errno.h @@ -21,6 +21,18 @@ * \file * \brief Error codes * \defgroup framework Celix Framework + * \details Error code has 32bits. If the value of error code is 0,it indicates success;if no-zero,it indicates error. + * its internal structure as following, + * + * |31-30bit|29bit|28-27bit|26-16bit|15-0bit| + * |-------:|:---:|:------:|:------:|:------| + * |R |C |R |Facility|Code | + * + * - C (1bit): Customer. If set, indicates that the error code is customer-defined. + * If clear, indicates that the error code is celix-defines. + * - R : Reserved. It should be set to 0. + * - Facility (11 bits): An indicator of the source of the error. + * - Code (16bits): The remainder of error code. */ #ifndef CELIX_ERRNO_H_ #define CELIX_ERRNO_H_ @@ -61,6 +73,44 @@ typedef int celix_status_t; */ const char* celix_strerror(celix_status_t status); +/*! + * Customer error code mask + * + */ +#define CELIX_CUSTOMER_ERR_MASK 0x20000000 + +/*! + * The facility of C errno, + * \note Error code 0 indicates success,it is not C errno. + */ +#define CELIX_FACILITY_CERRNO 0 + +/*! + * The facility of celix default error code + * + */ +#define CELIX_FACILITY_FRAMEWORK 1 + +/*! + * The facility of the http suppoter error code + * + */ +#define CELIX_FACILITY_HTTP 2 + +/*! + * Make the error code accroding to the specification + * \param fac Facility + * \param code Code + */ +#define CELIX_ERROR_MAKE(fac,code) (((unsigned int)(fac)<<16) | ((code)&0xFFFF)) + +/*! + * Make the customer error code + * \param usrFac Facility value of customer error code.It is defined by customer + * \param usrCode Code value of customer error codes.It is defined by customer + */ +#define CELIX_CUSTOMER_ERROR_MAKE(usrFac,usrCode) (CELIX_CUSTOMER_ERR_MASK | (((usrFac)&0x7FF)<<16) | ((usrCode)&0xFFFF)) + /*! * Error code indicating successful execution of the function. */ @@ -73,34 +123,59 @@ const char* celix_strerror(celix_status_t status); /*! * The range for Celix errors. + * \deprecated It is recommended to use facility indicate the range of error codes */ #define CELIX_ERRSPACE_SIZE 1000 /*! * The start error number user application can use. + * \deprecated It is recommended to use CELIX_CUSTOMER_ERR_MASK to define user error number */ #define CELIX_START_USERERR (CELIX_START_ERROR + CELIX_ERRSPACE_SIZE) +/*! + * @name celix default error codes + * @{ + */ + /*! * Exception indicating a problem with a bundle */ -#define CELIX_BUNDLE_EXCEPTION (CELIX_START_ERROR + 1) +#define CELIX_BUNDLE_EXCEPTION CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4465) + /*! * Invalid bundle context is used */ -#define CELIX_INVALID_BUNDLE_CONTEXT (CELIX_START_ERROR + 2) +#define CELIX_INVALID_BUNDLE_CONTEXT CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4466) /*! * Argument is not correct */ -#define CELIX_ILLEGAL_ARGUMENT (CELIX_START_ERROR + 3) -#define CELIX_INVALID_SYNTAX (CELIX_START_ERROR + 4) -#define CELIX_FRAMEWORK_SHUTDOWN (CELIX_START_ERROR + 5) -#define CELIX_ILLEGAL_STATE (CELIX_START_ERROR + 6) -#define CELIX_FRAMEWORK_EXCEPTION (CELIX_START_ERROR + 7) -#define CELIX_FILE_IO_EXCEPTION (CELIX_START_ERROR + 8) -#define CELIX_SERVICE_EXCEPTION (CELIX_START_ERROR + 9) +#define CELIX_ILLEGAL_ARGUMENT CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4467) +#define CELIX_INVALID_SYNTAX CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4468) +#define CELIX_FRAMEWORK_SHUTDOWN CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4469) +#define CELIX_ILLEGAL_STATE CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4470) +#define CELIX_FRAMEWORK_EXCEPTION CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4471) +#define CELIX_FILE_IO_EXCEPTION CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4472) +#define CELIX_SERVICE_EXCEPTION CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4473) +/*! + * Exception indicating a problem with a interceptor + */ +#define CELIX_INTERCEPTOR_EXCEPTION CELIX_ERROR_MAKE(CELIX_FACILITY_FRAMEWORK, 4474) + + +/*! @} *///celix default error codes + + +/*! + * @name C error map to celix + * @{ + */ + +#define CELIX_ENOMEM CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,ENOMEM) + + +/*! @}*///C error map to celix -#define CELIX_ENOMEM ENOMEM /** * \}