diff --git a/bundles/http_admin/http_admin/src/http_admin.c b/bundles/http_admin/http_admin/src/http_admin.c index a7e885b74..fb7ac6be0 100755 --- a/bundles/http_admin/http_admin/src/http_admin.c +++ b/bundles/http_admin/http_admin/src/http_admin.c @@ -37,7 +37,7 @@ struct http_admin_manager { struct mg_context *mgCtx; char *root; - celix_thread_mutex_t admin_lock; //protects below + celix_thread_rwlock_t admin_lock; //protects below celix_http_info_service_t infoSvc; long infoSvcId; @@ -70,7 +70,7 @@ http_admin_manager_t *httpAdmin_create(celix_bundle_context_t *context, char *ro admin->root = root; admin->infoSvcId = -1L; - status = celixThreadMutex_create(&admin->admin_lock, NULL); + status = celixThreadRwlock_create(&admin->admin_lock, NULL); admin->aliasList = celix_arrayList_create(); if (status == CELIX_SUCCESS) { @@ -93,7 +93,7 @@ http_admin_manager_t *httpAdmin_create(celix_bundle_context_t *context, char *ro if (admin->mgCtx != NULL) { mg_stop(admin->mgCtx); } - celixThreadMutex_destroy(&admin->admin_lock); + celixThreadRwlock_destroy(&admin->admin_lock); celix_arrayList_destroy(admin->aliasList); free(admin); @@ -103,14 +103,13 @@ http_admin_manager_t *httpAdmin_create(celix_bundle_context_t *context, char *ro } void httpAdmin_destroy(http_admin_manager_t *admin) { - celixThreadMutex_lock(&(admin->admin_lock)); if(admin->mgCtx != NULL) { mg_stop(admin->mgCtx); } + celixThreadRwlock_writeLock(&(admin->admin_lock)); celix_bundleContext_unregisterService(admin->context, admin->infoSvcId); - destroyServiceTree(&admin->http_svc_tree); //Destroy alias map by removing symbolic links first. @@ -129,8 +128,8 @@ void httpAdmin_destroy(http_admin_manager_t *admin) { } celix_arrayList_destroy(admin->aliasList); - celixThreadMutex_unlock(&(admin->admin_lock)); - celixThreadMutex_destroy(&(admin->admin_lock)); + celixThreadRwlock_unlock(&(admin->admin_lock)); + celixThreadRwlock_destroy(&(admin->admin_lock)); free(admin->root); free(admin); @@ -147,11 +146,10 @@ void http_admin_addHttpService(void *handle, void *svc, const celix_properties_t const char *uri = celix_properties_get(props, HTTP_ADMIN_URI, NULL); if(uri != NULL) { - celixThreadMutex_lock(&(admin->admin_lock)); + celix_auto(celix_rwlock_wlock_guard_t) lock = celixRwlockWlockGuard_init(&(admin->admin_lock)); if(!addServiceNode(&admin->http_svc_tree, uri, httpSvc)) { printf("HTTP service with URI %s already exists!\n", uri); } - celixThreadMutex_unlock(&(admin->admin_lock)); } } @@ -161,7 +159,7 @@ void http_admin_removeHttpService(void *handle, void *svc CELIX_UNUSED, const ce const char *uri = celix_properties_get(props, HTTP_ADMIN_URI, NULL); if(uri != NULL) { - celixThreadMutex_lock(&(admin->admin_lock)); + celix_auto(celix_rwlock_wlock_guard_t) lock = celixRwlockWlockGuard_init(&(admin->admin_lock)); service_tree_node_t *node = NULL; node = findServiceNodeInTree(&admin->http_svc_tree, uri); @@ -171,8 +169,6 @@ void http_admin_removeHttpService(void *handle, void *svc CELIX_UNUSED, const ce } else { printf("Couldn't remove HTTP service with URI: %s, it doesn't exist\n", uri); } - - celixThreadMutex_unlock(&(admin->admin_lock)); } } @@ -189,6 +185,7 @@ int http_request_handle(struct mg_connection *connection) { ret_status = 0; //... so return zero to let the civetweb server handle the request. } else { + celix_auto(celix_rwlock_rlock_guard_t) lock = celixRwlockRlockGuard_init(&(admin->admin_lock)); const char *req_uri = ri->request_uri; node = findServiceNodeInTree(&admin->http_svc_tree, req_uri); @@ -367,7 +364,7 @@ static void httpAdmin_updateInfoSvc(http_admin_manager_t *admin) { } fclose(stream); - celixThreadMutex_lock(&admin->admin_lock); + celix_auto(celix_rwlock_wlock_guard_t) lock = celixRwlockWlockGuard_init(&(admin->admin_lock)); celix_bundleContext_unregisterService(admin->context, admin->infoSvcId); celix_properties_t *properties = celix_properties_create(); @@ -377,8 +374,6 @@ static void httpAdmin_updateInfoSvc(http_admin_manager_t *admin) { } admin->infoSvcId = celix_bundleContext_registerService(admin->context, &admin->infoSvc, HTTP_ADMIN_INFO_SERVICE_NAME, properties); - celixThreadMutex_unlock(&admin->admin_lock); - free(resources_urls); } diff --git a/bundles/http_admin/http_admin/src/websocket_admin.c b/bundles/http_admin/http_admin/src/websocket_admin.c index 503bbf917..2cd8a4531 100644 --- a/bundles/http_admin/http_admin/src/websocket_admin.c +++ b/bundles/http_admin/http_admin/src/websocket_admin.c @@ -35,7 +35,7 @@ struct websocket_admin_manager { struct mg_context *mg_ctx; service_tree_t sock_svc_tree; - celix_thread_mutex_t admin_lock; + celix_thread_rwlock_t admin_lock; }; websocket_admin_manager_t *websocketAdmin_create(celix_bundle_context_t *context, struct mg_context *svr_ctx) { @@ -49,7 +49,7 @@ websocket_admin_manager_t *websocketAdmin_create(celix_bundle_context_t *context admin->context = context; admin->mg_ctx = svr_ctx; - status = celixThreadMutex_create(&admin->admin_lock, NULL); + status = celixThreadRwlock_create(&admin->admin_lock, NULL); if(status != CELIX_SUCCESS) { //No need to destroy other things @@ -60,14 +60,14 @@ websocket_admin_manager_t *websocketAdmin_create(celix_bundle_context_t *context } void websocketAdmin_destroy(websocket_admin_manager_t *admin) { - celixThreadMutex_lock(&(admin->admin_lock)); + celixThreadRwlock_writeLock(&(admin->admin_lock)); //Destroy tree with services destroyServiceTree(&admin->sock_svc_tree); - celixThreadMutex_unlock(&(admin->admin_lock)); + celixThreadRwlock_unlock(&(admin->admin_lock)); - celixThreadMutex_destroy(&(admin->admin_lock)); + celixThreadRwlock_destroy(&(admin->admin_lock)); free(admin); } @@ -79,14 +79,13 @@ void websocket_admin_addWebsocketService(void *handle, void *svc, const celix_pr const char *uri = celix_properties_get(props, WEBSOCKET_ADMIN_URI, NULL); if(uri != NULL) { - celixThreadMutex_lock(&(admin->admin_lock)); + celix_auto(celix_rwlock_wlock_guard_t) lock = celixRwlockWlockGuard_init(&(admin->admin_lock)); if(addServiceNode(&admin->sock_svc_tree, uri, websockSvc)) { mg_set_websocket_handler(admin->mg_ctx, uri, websocket_connect_handler, websocket_ready_handler, websocket_data_handler, websocket_close_handler, admin); } else { printf("Websocket service with URI %s already exists!\n", uri); } - celixThreadMutex_unlock(&(admin->admin_lock)); } } @@ -96,7 +95,7 @@ void websocket_admin_removeWebsocketService(void *handle, void *svc CELIX_UNUSED const char *uri = celix_properties_get(props, WEBSOCKET_ADMIN_URI, NULL); if(uri != NULL) { - celixThreadMutex_lock(&(admin->admin_lock)); + celix_auto(celix_rwlock_wlock_guard_t) lock = celixRwlockWlockGuard_init(&(admin->admin_lock)); service_tree_node_t *node = NULL; node = findServiceNodeInTree(&admin->sock_svc_tree, uri); @@ -107,7 +106,6 @@ void websocket_admin_removeWebsocketService(void *handle, void *svc CELIX_UNUSED printf("Couldn't remove websocket service with URI: %s, it doesn't exist\n", uri); } - celixThreadMutex_unlock(&(admin->admin_lock)); } } @@ -120,6 +118,7 @@ int websocket_connect_handler(const struct mg_connection *connection, void *hand const char *req_uri = ri->request_uri; service_tree_node_t *node = NULL; + celix_auto(celix_rwlock_rlock_guard_t) lock = celixRwlockRlockGuard_init(&(admin->admin_lock)); node = findServiceNodeInTree(&admin->sock_svc_tree, req_uri); if(node != NULL) { @@ -147,6 +146,7 @@ void websocket_ready_handler(struct mg_connection *connection, void *handle) { const char *req_uri = ri->request_uri; service_tree_node_t *node = NULL; + celix_auto(celix_rwlock_rlock_guard_t) lock = celixRwlockRlockGuard_init(&(admin->admin_lock)); node = findServiceNodeInTree(&admin->sock_svc_tree, req_uri); if(node != NULL) { @@ -169,6 +169,7 @@ int websocket_data_handler(struct mg_connection *connection, int op_code, char * const char *req_uri = ri->request_uri; service_tree_node_t *node = NULL; + celix_auto(celix_rwlock_rlock_guard_t) lock = celixRwlockRlockGuard_init(&(admin->admin_lock)); node = findServiceNodeInTree(&admin->sock_svc_tree, req_uri); if(node != NULL) { @@ -192,6 +193,7 @@ void websocket_close_handler(const struct mg_connection *connection, void *handl const char *req_uri = ri->request_uri; service_tree_node_t *node = NULL; + celix_auto(celix_rwlock_rlock_guard_t) lock = celixRwlockRlockGuard_init(&(admin->admin_lock)); node = findServiceNodeInTree(&admin->sock_svc_tree, req_uri); if(node != NULL) { diff --git a/bundles/remote_services/discovery_common/src/discovery_activator.c b/bundles/remote_services/discovery_common/src/discovery_activator.c index c1b441115..0b6b591f5 100644 --- a/bundles/remote_services/discovery_common/src/discovery_activator.c +++ b/bundles/remote_services/discovery_common/src/discovery_activator.c @@ -106,7 +106,7 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context int rc = asprintf(&scope, "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); status = rc < 0 ? CELIX_ENOMEM : CELIX_SUCCESS; - celix_properties_t *props = NULL; + celix_autoptr(celix_properties_t) props = NULL; if (status == CELIX_SUCCESS) { celix_logHelper_debug(activator->loghelper, "using scope %s.", scope); @@ -131,16 +131,14 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context endpointListener->endpointAdded = discovery_endpointAdded; endpointListener->endpointRemoved = discovery_endpointRemoved; - status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, props, &activator->endpointListenerService); + status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, + celix_steal_ptr(props), &activator->endpointListenerService); if (status == CELIX_SUCCESS) { activator->endpointListener = endpointListener; } } - } else { - celix_properties_destroy(props); - } - + } // We can release the scope, as celix_properties_set makes a copy of the key & value... free(scope); 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 a0488ed0f..e1a39812a 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 @@ -190,8 +190,8 @@ static void* importRegistration_getService(void *handle, const celix_bundle_t *r void importRegistration_ungetService(void *handle, const celix_bundle_t *requestingBundle, const celix_properties_t *svcProperties) { import_registration_t* import = handle; assert(import != NULL); - assert(import->proxies != NULL); pthread_mutex_lock(&import->proxiesMutex); + assert(import->proxies != NULL); struct service_proxy *proxy = hashMap_get(import->proxies, requestingBundle); if (proxy != NULL) { proxy->count -= 1; diff --git a/examples/celix-examples/dm_example/phase2a/src/phase2a_cmp.c b/examples/celix-examples/dm_example/phase2a/src/phase2a_cmp.c index f6884984f..07df43cb1 100644 --- a/examples/celix-examples/dm_example/phase2a/src/phase2a_cmp.c +++ b/examples/celix-examples/dm_example/phase2a/src/phase2a_cmp.c @@ -112,6 +112,8 @@ static void *phase2a_thread(void *data) { } int phase2a_getData(phase2a_cmp_t *cmp, double *data) { + celixThreadMutex_lock(&cmp->mutex); *data = cmp->currentValue; + celixThreadMutex_unlock(&cmp->mutex); return 0; } diff --git a/examples/celix-examples/dm_example/phase2b/src/phase2b_cmp.c b/examples/celix-examples/dm_example/phase2b/src/phase2b_cmp.c index a73415097..8cac46312 100644 --- a/examples/celix-examples/dm_example/phase2b/src/phase2b_cmp.c +++ b/examples/celix-examples/dm_example/phase2b/src/phase2b_cmp.c @@ -111,6 +111,8 @@ static void *phase2b_thread(void *data) { } int phase2b_getData(phase2b_cmp_t *cmp, double *data) { + celixThreadMutex_lock(&cmp->mutex); *data = cmp->currentValue; + celixThreadMutex_unlock(&cmp->mutex); return 0; } diff --git a/libs/dfi/gtest/descriptors/example4.descriptor b/libs/dfi/gtest/descriptors/example4.descriptor index 4c959c4dd..77a7a7f50 100644 --- a/libs/dfi/gtest/descriptors/example4.descriptor +++ b/libs/dfi/gtest/descriptors/example4.descriptor @@ -6,3 +6,5 @@ version=1.0.0 :types :methods getName(V)t=getName(#am=handle;P#am=out;*t)N +setName=setName(#am=handle;Pt)N +setConstName=setConstName(#am=handle;P#const=true;t)N diff --git a/libs/dfi/gtest/descriptors/example6.descriptor b/libs/dfi/gtest/descriptors/example6.descriptor new file mode 100644 index 000000000..4ce4e9357 --- /dev/null +++ b/libs/dfi/gtest/descriptors/example6.descriptor @@ -0,0 +1,9 @@ +:header +type=interface +name=example6 +version=1.0.0 +:annotations +:types +CptData={Dt[D#v1=1;#v2=2;E d t s e} +:methods +compatibility=cpt(#am=handle;PLCptData;#am=out;*LCptData;)N diff --git a/libs/dfi/gtest/descriptors/invalids/invalidHeader.descriptor b/libs/dfi/gtest/descriptors/invalids/invalidHeader.descriptor new file mode 100644 index 000000000..5afd8dd3e --- /dev/null +++ b/libs/dfi/gtest/descriptors/invalids/invalidHeader.descriptor @@ -0,0 +1,9 @@ +:header +type=interface +name= +version=1.0.0 +:annotations +:types +item={DD a b} +:methods +example1=items(#am=handle;P#am=out;**[Litem;)N \ No newline at end of file diff --git a/libs/dfi/gtest/src/dyn_interface_tests.cpp b/libs/dfi/gtest/src/dyn_interface_tests.cpp index f254ef4f0..2ddaa1473 100644 --- a/libs/dfi/gtest/src/dyn_interface_tests.cpp +++ b/libs/dfi/gtest/src/dyn_interface_tests.cpp @@ -128,6 +128,12 @@ extern "C" { ASSERT_EQ(1, status); //Test fails because of a space at the end of the name fclose(desc); desc=NULL; + /* Invalid header */ + desc = fopen("descriptors/invalids/invalidHeader.descriptor", "r"); + assert(desc != NULL); + status = dynInterface_parse(desc, &dynIntf); + ASSERT_EQ(1, status); //Test fails because of missing name value + fclose(desc); desc=NULL; /* Header without Version */ desc = fopen("descriptors/invalids/noVersion.descriptor", "r"); diff --git a/libs/dfi/gtest/src/dyn_type_tests.cpp b/libs/dfi/gtest/src/dyn_type_tests.cpp index 2427f1ae8..9cb23876a 100644 --- a/libs/dfi/gtest/src/dyn_type_tests.cpp +++ b/libs/dfi/gtest/src/dyn_type_tests.cpp @@ -24,6 +24,7 @@ extern "C" { #include "dyn_common.h" #include "dyn_type.h" + #include "celix_err.h" static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) { va_list ap; @@ -323,4 +324,52 @@ TEST_F(DynTypeTests, NrOfEntriesTest) { ASSERT_EQ(0, rc); ASSERT_EQ(4, dynType_complex_nrOfEntries(type)); dynType_destroy(type); +} + +TEST_F(DynTypeTests, ComplexHasEmptyName) { + dyn_type *type = NULL; + auto rc = dynType_parseWithStr(R"({II a })", nullptr, nullptr, &type); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); +} + +TEST_F(DynTypeTests, SchemaEndsWithoutNullTerminator) { + dyn_type *type = NULL; + //ends with '-' + auto rc = dynType_parseWithStr(R"({II a b}-)", nullptr, nullptr, &type); + ASSERT_EQ(3, rc); + celix_err_printErrors(stderr, nullptr, nullptr); +} + +TEST_F(DynTypeTests, MetaInfoMissingValue) { + dyn_type *type = NULL; + auto rc = dynType_parseWithStr(R"(#testMetaInfo=)", nullptr, nullptr, &type); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); +} + +TEST_F(DynTypeTests, ParseNestedTypeFailed) { + dyn_type *type = NULL; + //missing '=' + auto rc = dynType_parseWithStr(R"(Ttype)", nullptr, nullptr, &type); + ASSERT_EQ(3, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + + //missing value + rc = dynType_parseWithStr(R"(Ttype=)", nullptr, nullptr, &type); + ASSERT_EQ(3, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + + //missing ';' + rc = dynType_parseWithStr(R"(Ttype={DD a b})", nullptr, nullptr, &type); + ASSERT_EQ(3, rc); + celix_err_printErrors(stderr, nullptr, nullptr); +} + +TEST_F(DynTypeTests, ParseReferenceFailed) { + dyn_type *type = NULL; + //missing ';' + auto rc = dynType_parseWithStr(R"(Ttype={DD a b};ltype)", nullptr, nullptr, &type); + ASSERT_EQ(3, rc); + celix_err_printErrors(stderr, nullptr, nullptr); } \ No newline at end of file diff --git a/libs/dfi/gtest/src/json_rpc_tests.cpp b/libs/dfi/gtest/src/json_rpc_tests.cpp index 2a67e4944..32e45663f 100644 --- a/libs/dfi/gtest/src/json_rpc_tests.cpp +++ b/libs/dfi/gtest/src/json_rpc_tests.cpp @@ -68,6 +68,73 @@ extern "C" { dynFunction_destroy(dynFunc); } + void prepareCharTest(void) { + dyn_function_type *dynFunc = nullptr; + int rc = dynFunction_parseWithStr("setName(#am=handle;Pt)N", nullptr, &dynFunc); + ASSERT_EQ(0, rc); + + char *result = nullptr; + + void *handle = nullptr; + char *arg1 = strdup("hello char"); + void *args[2]; + args[0] = &handle; + args[1] = &arg1; + + rc = jsonRpc_prepareInvokeRequest(dynFunc, "setName", args, &result); + ASSERT_EQ(0, rc); + + ASSERT_TRUE(strstr(result, "\"setName\"") != nullptr); + ASSERT_TRUE(strstr(result, "hello char") != nullptr); + + free(result); + dynFunction_destroy(dynFunc); + } + + void prepareConstCharTest(void) { + dyn_function_type *dynFunc = nullptr; + int rc = dynFunction_parseWithStr("setConstName(#am=handle;P#const=true;t)N", nullptr, &dynFunc); + ASSERT_EQ(0, rc); + + char *result = nullptr; + + void *handle = nullptr; + const char *arg1 = "hello const char"; + void *args[2]; + args[0] = &handle; + args[1] = &arg1; + + rc = jsonRpc_prepareInvokeRequest(dynFunc, "setConstName", args, &result); + ASSERT_EQ(0, rc); + + ASSERT_TRUE(strstr(result, "\"setConstName\"") != nullptr); + ASSERT_TRUE(strstr(result, "hello const char") != nullptr); + + free(result); + dynFunction_destroy(dynFunc); + } + + void prepareTestFailed(void) { + dyn_function_type *dynFunc = nullptr; + int rc = dynFunction_parseWithStr("action(#am=handle;PP)N", nullptr, &dynFunc); + ASSERT_EQ(0, rc); + + char *result = nullptr; + + void *handle = nullptr; + void *arg1 = nullptr; + void *args[2]; + args[0] = &handle; + args[1] = &arg1; + + rc = jsonRpc_prepareInvokeRequest(dynFunc, "action", args, &result); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + + free(result); + dynFunction_destroy(dynFunc); + } + void handleTestPre(void) { dyn_function_type *dynFunc = nullptr; int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", nullptr, &dynFunc); @@ -87,6 +154,26 @@ extern "C" { dynFunction_destroy(dynFunc); } + + void handleTestInvalidReply(void) { + dyn_function_type *dynFunc = nullptr; + int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", nullptr, &dynFunc); + ASSERT_EQ(0, rc); + + double result = -1.0; + double *out = &result; + void *args[4]; + args[3] = &out; + int rsErrno = 0; + rc = jsonRpc_handleReply(dynFunc, "invalid", args, &rsErrno); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + + dynFunction_destroy(dynFunc); + } + + + int add(void*, double a, double b, double *result) { *result = a + b; return 0; @@ -175,6 +262,8 @@ extern "C" { struct tst_serv_example4 { void *handle; int (*getName_example4)(void *, char** name); + int (*setName_example4)(void *, char* name); + int (*setConstName_example4)(void *, const char* name); }; void callTestPreAllocated(void) { @@ -251,6 +340,10 @@ extern "C" { rc = jsonRpc_call(intf, &serv, R"({"a": [1.0,2.0]})", &result); ASSERT_EQ(1, rc); + //request argument type mismatch + rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;", "a": [1.0]})", &result); + ASSERT_EQ(1, rc); + dynInterface_destroy(intf); } @@ -376,6 +469,23 @@ extern "C" { dynInterface_destroy(intf); } + void callTestUnknownRequest(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":"unknown", "a": [1.0,2.0]})", &result); + ASSERT_EQ(1, rc); + + dynInterface_destroy(intf); + } + static void handleTestOutputSequence() { dyn_interface_type *intf = nullptr; FILE *desc = fopen("descriptors/example2.descriptor", "r"); @@ -559,7 +669,7 @@ extern "C" { fclose(desc); char *result = nullptr; - tst_serv_example4 serv {nullptr, getName_example4}; + tst_serv_example4 serv {nullptr, getName_example4, nullptr, nullptr}; rc = jsonRpc_call(intf, &serv, R"({"m": "getName(V)t", "a": []})", &result); ASSERT_EQ(0, rc); @@ -611,6 +721,222 @@ extern "C" { free(result); dynInterface_destroy(intf); } + + void handleTestPreChar(void) { + dyn_function_type *dynFunc = nullptr; + int rc = dynFunction_parseWithStr("getName(#am=handle;P#am=pre;t)N", nullptr, &dynFunc); + ASSERT_EQ(0, rc); + + const char *reply = "{\"r\":\"this is a test pre string\"}"; + char result[32] = {0}; + void *out = result; + void *args[2]; + args[0] = nullptr; + args[1] = &out; + int rsErrno = 0; + rc = jsonRpc_handleReply(dynFunc, reply, args, &rsErrno); + ASSERT_EQ(0, rc); + ASSERT_EQ(0, rsErrno); + ASSERT_STREQ("this is a test pre string", result); + + dynFunction_destroy(dynFunc); + } + + void callTestChar(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example4.descriptor", "r"); + ASSERT_TRUE(desc != nullptr); + int rc = dynInterface_parse(desc, &intf); + ASSERT_EQ(0, rc); + fclose(desc); + + char *result = nullptr; + tst_serv_example4 serv {nullptr, nullptr,[](void*, char *name)->int { + EXPECT_STREQ(name, "hello"); + free(name); + return 0; + }, nullptr}; + + rc = jsonRpc_call(intf, &serv, R"({"m": "setName", "a":["hello"]})", &result); + ASSERT_EQ(0, rc); + free(result); + + dynInterface_destroy(intf); + } + + void callTestConstChar(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example4.descriptor", "r"); + ASSERT_TRUE(desc != nullptr); + int rc = dynInterface_parse(desc, &intf); + ASSERT_EQ(0, rc); + fclose(desc); + + char *result = nullptr; + tst_serv_example4 serv {nullptr, nullptr, nullptr, [](void*, const char *name)->int { + EXPECT_STREQ(name, "hello const char"); + return 0; + }}; + + rc = jsonRpc_call(intf, &serv, R"({"m": "setConstName", "a":["hello const char"]})", &result); + ASSERT_EQ(0, rc); + free(result); + + dynInterface_destroy(intf); + } + + enum example6_enum{ + v1 = 1, + v2 = 2, + }; + + struct tst_CptData { + double d; + char *t; + struct tst_seq s; + enum example6_enum e; + }; + + struct tst_serv_example6 { + void *handle; + int (*cpt)(void *, struct tst_CptData *input, struct tst_CptData *output); + }; + + void testRequestBackwardCompatibility(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example6.descriptor", "r"); + ASSERT_TRUE(desc != nullptr); + int rc = dynInterface_parse(desc, &intf); + ASSERT_EQ(0, rc); + fclose(desc); + + + char *result = nullptr; + + tst_serv_example6 serv {nullptr, nullptr}; + + serv.cpt = [](void *, struct tst_CptData *input, struct tst_CptData *)->int { + EXPECT_EQ(input->d , 0.0); + EXPECT_EQ(input->t , nullptr); + EXPECT_EQ(input->s.len , 0); + EXPECT_EQ(input->s.cap , 0); + EXPECT_EQ(input->s.buf , nullptr); + EXPECT_EQ(input->e , 0); + return 0; + }; + rc = jsonRpc_call(intf, &serv, R"({"m": "compatibility", "a": [{}]})", &result); + ASSERT_EQ(0, rc); + free(result); + + serv.cpt = [](void *, struct tst_CptData *input, struct tst_CptData *)->int { + EXPECT_EQ(input->d , 1.0); + EXPECT_EQ(input->t , nullptr); + EXPECT_EQ(input->s.len , 0); + EXPECT_EQ(input->s.cap , 0); + EXPECT_EQ(input->s.buf , nullptr); + EXPECT_EQ(input->e , 0); + return 0; + }; + rc = jsonRpc_call(intf, &serv, R"({"m": "compatibility", "a": [{"d":1.0}]})", &result); + ASSERT_EQ(0, rc); + free(result); + + serv.cpt = [](void *, struct tst_CptData *input, struct tst_CptData *)->int { + EXPECT_EQ(input->d , 1.0); + EXPECT_STREQ(input->t , "hello compatibility"); + EXPECT_EQ(input->s.len , 0); + EXPECT_EQ(input->s.cap , 0); + EXPECT_EQ(input->s.buf , nullptr); + EXPECT_EQ(input->e , 0); + return 0; + }; + rc = jsonRpc_call(intf, &serv, R"({"m": "compatibility", "a": [{"d":1.0, "t":"hello compatibility"}]})", &result); + ASSERT_EQ(0, rc); + free(result); + + serv.cpt = [](void *, struct tst_CptData *input, struct tst_CptData *)->int { + EXPECT_EQ(input->d , 1.0); + EXPECT_STREQ(input->t , "hello compatibility"); + EXPECT_EQ(input->s.len , 3); + EXPECT_EQ(input->s.cap , 3); + EXPECT_EQ(input->s.buf[0] , 1.0); + EXPECT_EQ(input->s.buf[1] , 2.0); + EXPECT_EQ(input->s.buf[2] , 3.0); + EXPECT_EQ(input->e , 0); + return 0; + }; + rc = jsonRpc_call(intf, &serv, R"({"m": "compatibility", "a": [{"d":1.0, "t":"hello compatibility", "s":[1.0,2.0,3.0]}]})", &result); + ASSERT_EQ(0, rc); + free(result); + + + serv.cpt = [](void *, struct tst_CptData *input, struct tst_CptData *)->int { + EXPECT_EQ(input->d , 1.0); + EXPECT_STREQ(input->t , "hello compatibility"); + EXPECT_EQ(input->s.len , 3); + EXPECT_EQ(input->s.cap , 3); + EXPECT_EQ(input->s.buf[0] , 1.0); + EXPECT_EQ(input->s.buf[1] , 2.0); + EXPECT_EQ(input->s.buf[2] , 3.0); + EXPECT_EQ(input->e , v2); + return 0; + }; + rc = jsonRpc_call(intf, &serv, R"({"m": "compatibility", "a": [{"d":1.0, "t":"hello compatibility", "s":[1.0,2.0,3.0], "e":"v2"}]})", &result); + ASSERT_EQ(0, rc); + free(result); + + + dynInterface_destroy(intf); + } + + void testResponseForwardCompatibility(void) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example6.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, "compatibility") == 0) { + func = entry->dynFunc; + break; + } + } + ASSERT_TRUE(func != nullptr); + + struct tst_CptData *cptData{nullptr}; + void *out = &cptData; + + void *args[3]; + args[0] = nullptr; + args[1] = nullptr; + args[2] = &out; + int rsErrno = 0; + + //provider has more reply + rc = jsonRpc_handleReply(func, R"({"r":{"d":1.0, "t":"hello compatibility", "s":[1.0,2.0,3.0], "e":"v1", "e2":"v2"}})", args, &rsErrno); + EXPECT_EQ(0, rc); + EXPECT_EQ(0, rsErrno); + EXPECT_NE(cptData , nullptr); + EXPECT_EQ(cptData->d , 1.0); + EXPECT_STREQ(cptData->t , "hello compatibility"); + EXPECT_EQ(cptData->s.len , 3); + EXPECT_EQ(cptData->s.cap , 3); + EXPECT_EQ(cptData->s.buf[0] , 1.0); + EXPECT_EQ(cptData->s.buf[1] , 2.0); + EXPECT_EQ(cptData->s.buf[2] , 3.0); + EXPECT_EQ(cptData->e , v1); + free(cptData->t); + free(cptData->s.buf); + free(cptData); + + dynInterface_destroy(intf); + } } class JsonRpcTests : public ::testing::Test { @@ -627,10 +953,26 @@ TEST_F(JsonRpcTests, prepareTest) { prepareTest(); } +TEST_F(JsonRpcTests, prepareCharTest) { + prepareCharTest(); +} + +TEST_F(JsonRpcTests, prepareConstCharTest) { + prepareConstCharTest(); +} + +TEST_F(JsonRpcTests, prepareTestFailed) { + prepareTestFailed(); +} + TEST_F(JsonRpcTests, handleTestPre) { handleTestPre(); } +TEST_F(JsonRpcTests, handleTestInvalidReply) { + handleTestInvalidReply(); +} + TEST_F(JsonRpcTests, handleTestOut) { handleTestOut(); } @@ -651,6 +993,10 @@ TEST_F(JsonRpcTests, callTestInvalidRequest) { callTestInvalidRequest(); } +TEST_F(JsonRpcTests, callTestUnknownRequest) { + callTestUnknownRequest(); +} + TEST_F(JsonRpcTests, handleOutSeq) { handleTestOutputSequence(); } @@ -663,6 +1009,10 @@ TEST_F(JsonRpcTests, handleOutChar) { handleTestOutChar(); } +TEST_F(JsonRpcTests, handlePreChar) { + handleTestPreChar(); +} + TEST_F(JsonRpcTests, handleReplyError) { handleTestReplyError(); } @@ -681,4 +1031,20 @@ TEST_F(JsonRpcTests, handleTestMultiPreOut) { TEST_F(JsonRpcTests, handleTestMultiOut) { handleTestMultiOut(); -} \ No newline at end of file +} + +TEST_F(JsonRpcTests, callTestChar) { + callTestChar(); +} + +TEST_F(JsonRpcTests, callTestConstChar) { + callTestConstChar(); +} + +TEST_F(JsonRpcTests, testRequestBackwardCompatibility) { + testRequestBackwardCompatibility(); +} + +TEST_F(JsonRpcTests, testResponseForwardCompatibility) { + testResponseForwardCompatibility(); +} diff --git a/libs/dfi/gtest/src/json_serializer_tests.cpp b/libs/dfi/gtest/src/json_serializer_tests.cpp index 3b7b125d2..ccfcedf94 100644 --- a/libs/dfi/gtest/src/json_serializer_tests.cpp +++ b/libs/dfi/gtest/src/json_serializer_tests.cpp @@ -32,6 +32,7 @@ extern "C" { #include "dyn_common.h" #include "dyn_type.h" #include "json_serializer.h" +#include "celix_err.h" static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) { va_list ap; @@ -991,6 +992,89 @@ static void parseTests() { check_exampleA(inst); dynType_free(type, inst); dynType_destroy(type); + + //parse ref by value + type = nullptr; + inst = nullptr; + rc = dynType_parseWithStr("Ttype={DD a b};ltype;", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + auto inputStr = R"({"a":1.0, "b":2.0})"; + json_error_t error; + json_auto_t *input = json_loadb(inputStr, strlen(inputStr), JSON_DECODE_ANY, &error); + rc = jsonSerializer_deserializeJson(type, input, &inst); + ASSERT_EQ(0, rc); + struct { + double a; + double b; + } *data = static_cast(inst); + ASSERT_EQ(1.0, data->a); + ASSERT_EQ(2.0, data->b); + dynType_free(type, inst); + dynType_destroy(type); + + //invalid input + type = nullptr; + inst = nullptr; + rc = dynType_parseWithStr("{DD a b}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + rc = jsonSerializer_deserialize(type, "invalid", strlen("invalid"), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //pointer type mismatch + rc = dynType_parseWithStr("{*t a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"({"a":1.0})"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //text type mismatch + rc = dynType_parseWithStr("{t a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"({"a":1.0})"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //enum type mismatch + rc = dynType_parseWithStr("{#v1=1;#v2=2;E a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"({"a":1.0})"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //enum value unknown + rc = dynType_parseWithStr("{#v1=1;#v2=2;E a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"({"a":"v3"})"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //sequence element type mismatch + rc = dynType_parseWithStr("[t", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"([1.0, 2.0])"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + + //unsupported untyped pointer + rc = dynType_parseWithStr("{P a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"({"a":1.0})"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); } /*********** write example 1 ************************/ @@ -1396,6 +1480,88 @@ void writeAvprTest3(void) { free(result); } +void writeEnum(void) { + dyn_type *type = nullptr; + char *result = nullptr; + int rc = dynType_parseWithStr(R"(#v1=1;#v2=2;E)", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + enum { + v1 = 1, + v2 = 2 + }enumVal = v2; + rc = jsonSerializer_serialize(type, &enumVal, &result); + ASSERT_EQ(0, rc); + ASSERT_TRUE(strstr(result, R"(v2)") != nullptr); + free(result); + dynType_destroy(type); +} + +void writeRefByVal(void) { + dyn_type *type = nullptr; + char *result = nullptr; + int rc = dynType_parseWithStr(R"(Ttype={DD a b};ltype;)", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + struct { + double a; + double b; + }input{1.0,2.0}; + rc = jsonSerializer_serialize(type, &input, &result); + ASSERT_EQ(0, rc); + ASSERT_TRUE(strstr(result, R"("a":1.0)") != nullptr); + ASSERT_TRUE(strstr(result, R"("b":2.0)") != nullptr); + free(result); + dynType_destroy(type); +} + +void writeSequenceFailed(void) { + dyn_type *type = nullptr; + char *result = nullptr; + int rc = dynType_parseWithStr(R"([D)", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + double input[] = {1.0,2.0}; + struct { + uint32_t cap; + uint32_t len; + double *buf; + }seq{1,2,input};//cap < len + rc = jsonSerializer_serialize(type, &seq, &result); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); +} + +void writeComplexFailed(void) { + dyn_type *type = nullptr; + char *result = nullptr; + //has unnamed complex element + int rc = dynType_parseWithStr(R"({II a})", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + struct { + int32_t a; + int32_t b; + }input{1,2}; + rc = jsonSerializer_serialize(type, &input, &result); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); +} + +void writeEnumFailed(void) { + dyn_type *type = nullptr; + char *result = nullptr; + int rc = dynType_parseWithStr(R"(#v1=1;#v2=2;E)", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + enum { + v1 = 1, + v2 = 2, + v3 = 3 + }enumVal = v3;//schema only has v1 and v2 + rc = jsonSerializer_serialize(type, &enumVal, &result); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); +} + } // extern "C" @@ -1437,3 +1603,22 @@ TEST_F(JsonSerializerTests, WriteTest3) { writeAvprTest3(); } +TEST_F(JsonSerializerTests, WriteEnum) { + writeEnum(); +} + +TEST_F(JsonSerializerTests, WriteRefByVal) { + writeRefByVal(); +} + +TEST_F(JsonSerializerTests, WriteSequenceFailed) { + writeSequenceFailed(); +} + +TEST_F(JsonSerializerTests, WriteComplexFailed) { + writeComplexFailed(); +} + +TEST_F(JsonSerializerTests, WriteEnumFailed) { + writeEnumFailed(); +} diff --git a/libs/dfi/src/dyn_avpr_type.c b/libs/dfi/src/dyn_avpr_type.c index 9482c5ca1..32c41fd82 100644 --- a/libs/dfi/src/dyn_avpr_type.c +++ b/libs/dfi/src/dyn_avpr_type.c @@ -691,7 +691,7 @@ static inline bool dynAvprType_metaEntrySetValue(struct meta_entry * meta_entry_ if (values_array) { const char* enumValue = json_string_value(json_array_get(values_array, index)); if (!enumValue) { - LOG_ERROR("MetaEntrySetValue: could not get the enum value from the \"EnumValues\" list at index %lu", index); + LOG_ERROR("MetaEntrySetValue: could not get the enum value from the \"EnumValues\" list at index %zu", index); return false; } @@ -706,7 +706,7 @@ static inline bool dynAvprType_metaEntrySetValue(struct meta_entry * meta_entry_ const size_t bufsize = sizeof(index) * CHAR_BIT + 1; meta_entry_ptr->value = calloc(bufsize, sizeof(char)); - snprintf(meta_entry_ptr->value, bufsize, "%lu", (long unsigned int) index); + snprintf(meta_entry_ptr->value, bufsize, "%zu", index); } return true; diff --git a/libs/dfi/src/dyn_function.c b/libs/dfi/src/dyn_function.c index dc09ec66c..1b6666cc8 100644 --- a/libs/dfi/src/dyn_function.c +++ b/libs/dfi/src/dyn_function.c @@ -93,7 +93,7 @@ int dynFunction_parse(FILE *descriptor, struct types_head *refTypes, dyn_functio int dynFunction_parseWithStr(const char *descriptor, struct types_head *refTypes, dyn_function_type **out) { int status = OK; - FILE *stream = fmemopen((char *)descriptor, strlen(descriptor), "r"); + FILE *stream = fmemopen((char *)descriptor, strlen(descriptor) + 1, "r"); if (stream != NULL) { status = dynFunction_parse(stream, refTypes, out); fclose(stream); diff --git a/libs/dfi/src/dyn_interface.c b/libs/dfi/src/dyn_interface.c index 9b208280c..9f702ce79 100644 --- a/libs/dfi/src/dyn_interface.c +++ b/libs/dfi/src/dyn_interface.c @@ -185,8 +185,8 @@ static int dynInterface_parseNameValueSection(dyn_interface_type *intf, FILE *st while (peek != ':' && peek != EOF) { ungetc(peek, stream); - char *name; - char *value; + char *name = NULL; + char *value = NULL; status = dynCommon_parseNameValue(stream, &name, &value); if (status == OK) { @@ -230,7 +230,7 @@ static int dynInterface_parseTypes(dyn_interface_type *intf, FILE *stream) { while (peek != ':' && peek != EOF) { ungetc(peek, stream); - char *name; + char *name = NULL; status = dynCommon_parseName(stream, &name); if (status == OK) { @@ -283,7 +283,7 @@ static int dynInterface_parseMethods(dyn_interface_type *intf, FILE *stream) { while (peek != ':' && peek != EOF) { ungetc(peek, stream); - char *id; + char *id = NULL; status = dynCommon_parseNameAlsoAccept(stream, ".();[{}/", &id); if (status == OK) { diff --git a/libs/dfi/src/dyn_message.c b/libs/dfi/src/dyn_message.c index 441a60612..0571be093 100644 --- a/libs/dfi/src/dyn_message.c +++ b/libs/dfi/src/dyn_message.c @@ -180,8 +180,8 @@ static int dynMessage_parseNameValueSection(dyn_message_type *msg, FILE *stream, while (peek != ':' && peek != EOF) { ungetc(peek, stream); - char *name; - char *value; + char *name = NULL; + char *value = NULL; status = dynCommon_parseNameValue(stream, &name, &value); if (status == OK) { diff --git a/libs/dfi/src/dyn_type.c b/libs/dfi/src/dyn_type.c index cf84dff2c..df2021bfd 100644 --- a/libs/dfi/src/dyn_type.c +++ b/libs/dfi/src/dyn_type.c @@ -88,13 +88,15 @@ int dynType_parse(FILE *descriptorStream, const char *name, struct types_head *r int dynType_parseWithStr(const char *descriptor, const char *name, struct types_head *refTypes, dyn_type **type) { int status = OK; - FILE *stream = fmemopen((char *)descriptor, strlen(descriptor), "r"); + FILE *stream = fmemopen((char *)descriptor, strlen(descriptor) + 1, "r"); if (stream != NULL) { status = dynType_parseWithStream(stream, name, NULL, refTypes, type); if (status == OK) { int c = fgetc(stream); if (c != '\0' && c != EOF) { status = PARSE_ERROR; + dynType_destroy(*type); + *type = NULL; LOG_ERROR("Expected EOF got %c", c); } } @@ -591,12 +593,16 @@ int dynType_alloc(dyn_type *type, void **bufLoc) { int dynType_complex_indexForName(dyn_type *type, const char *name) { assert(type->type == DYN_TYPE_COMPLEX); + if (name == NULL) { + return -1; + } int i = 0; int index = -1; struct complex_type_entry *entry = NULL; TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) { - if (strcmp(name, entry->name) == 0) { + if (entry->name != NULL && strcmp(name, entry->name) == 0) { index = i; + break; } i +=1; } @@ -662,7 +668,7 @@ int dynType_sequence_alloc(dyn_type *type, void *inst, uint32_t cap) { struct generic_sequence *seq = inst; if (seq != NULL) { size_t size = dynType_size(type->sequence.itemType); - seq->buf = malloc(cap * size); + seq->buf = calloc(cap, size); if (seq->buf != NULL) { seq->cap = cap; seq->len = 0; diff --git a/libs/dfi/src/json_rpc.c b/libs/dfi/src/json_rpc.c index ad864c984..c2f7f43dc 100644 --- a/libs/dfi/src/json_rpc.c +++ b/libs/dfi/src/json_rpc.c @@ -230,7 +230,7 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c } else { json_object_set_new_nocheck(payload, "e", json_integer(funcCallStatus)); } - response = json_dumps(payload, JSON_DECODE_ANY); + response = json_dumps(payload, JSON_COMPACT | JSON_ENCODE_ANY);//Should use JSON_COMPACT, it can reduce the size of the JSON string. json_decref(payload); } @@ -285,12 +285,15 @@ int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void * } } - char *invokeStr = json_dumps(invoke, JSON_DECODE_ANY); + char *invokeStr = json_dumps(invoke, JSON_COMPACT | JSON_ENCODE_ANY);//Should use JSON_COMPACT, it can reduce the size of the JSON string. json_decref(invoke); if (status == OK) { *out = invokeStr; - } + } else { + *out = NULL; + free(invokeStr); + } return status; } @@ -315,7 +318,7 @@ int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[] rsError = json_object_get(replyJson, "e"); if(rsError != NULL) { //get the invocation error of remote service function - *rsErrno = json_integer_value(rsError); + *rsErrno = (int)json_integer_value(rsError); replyHasError = true; } } diff --git a/libs/dfi/src/json_serializer.c b/libs/dfi/src/json_serializer.c index c4668866f..e24cc58d4 100644 --- a/libs/dfi/src/json_serializer.c +++ b/libs/dfi/src/json_serializer.c @@ -128,8 +128,7 @@ static int jsonSerializer_parseObjectMember(dyn_type *type, const char *name, js int index = dynType_complex_indexForName(type, name); if (index < 0) { - LOG_ERROR("Cannot find index for member '%s'", name); - status = ERROR; + return OK;//We should ignore unknown name in request or response. Satisfy forward compatibility for responses. } if (status == OK) { @@ -311,7 +310,7 @@ int jsonSerializer_serialize(dyn_type *type, const void* input, char **output) { status = jsonSerializer_serializeJson(type, input, &root); if (status == OK) { - *output = json_dumps(root, JSON_COMPACT); + *output = json_dumps(root, JSON_COMPACT | JSON_ENCODE_ANY); json_decref(root); } @@ -411,7 +410,7 @@ static int jsonSerializer_writeAny(dyn_type *type, void* input, json_t **out) { break; case 'E': e = input; - jsonSerializer_writeEnum(type, *e, &val); + status = jsonSerializer_writeEnum(type, *e, &val); break; case '*' : status = dynType_typedPointer_getTypedType(type, &subType); @@ -474,6 +473,9 @@ static int jsonSerializer_writeSequence(dyn_type *type, void *input, json_t **ou if (status == OK && array != NULL) { *out = array; + } else { + *out = NULL; + json_decref(array); } return status; @@ -521,6 +523,9 @@ static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **out if (status == OK && val != NULL) { *out = val; + } else { + *out = NULL; + json_decref(val); } return status; diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c index a28fa533f..2cfdf9791 100644 --- a/libs/framework/src/framework.c +++ b/libs/framework/src/framework.c @@ -297,7 +297,6 @@ celix_status_t framework_destroy(framework_pt framework) { celix_serviceRegistry_destroy(framework->registry); - celixThreadMutex_lock(&framework->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(framework->installedBundles.entries); ++i) { celix_framework_bundle_entry_t *entry = celix_arrayList_get(framework->installedBundles.entries, i); celixThreadMutex_lock(&entry->useMutex); @@ -336,7 +335,6 @@ celix_status_t framework_destroy(framework_pt framework) { bundle_destroy(bnd); } - celixThreadMutex_unlock(&framework->installedBundles.mutex); celix_arrayList_destroy(framework->installedBundles.entries); celixThreadMutex_destroy(&framework->installedBundles.mutex); celixThreadMutex_destroy(&framework->installLock); @@ -2399,7 +2397,7 @@ void celix_framework_updateBundleAsync(celix_framework_t *fw, long bndId, const static celix_array_list_t* celix_framework_listBundlesInternal(celix_framework_t* framework, bool activeOnly) { celix_array_list_t* result = celix_arrayList_create(); - celixThreadMutex_lock(&framework->dispatcher.mutex); + celix_auto(celix_mutex_lock_guard_t) lock = celixMutexLockGuard_init(&framework->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(framework->installedBundles.entries); ++i) { celix_framework_bundle_entry_t* entry = celix_arrayList_get(framework->installedBundles.entries, i); if (entry->bndId == CELIX_FRAMEWORK_BUNDLE_ID) { @@ -2411,7 +2409,6 @@ static celix_array_list_t* celix_framework_listBundlesInternal(celix_framework_t celix_arrayList_addLong(result, entry->bndId); } } - celixThreadMutex_unlock(&framework->dispatcher.mutex); return result; } diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c index 14c1aedb8..7f1958703 100644 --- a/libs/framework/src/service_registry.c +++ b/libs/framework/src/service_registry.c @@ -82,7 +82,7 @@ celix_service_registry_t* celix_serviceRegistry_create(framework_pt framework) { } void celix_serviceRegistry_destroy(celix_service_registry_t* registry) { - celixThreadRwlock_writeLock(®istry->lock); + celixThreadRwlock_destroy(®istry->lock); //remove service listeners int size = celix_arrayList_size(registry->serviceListeners);