diff --git a/libs/dfi/gtest/descriptors/example7.descriptor b/libs/dfi/gtest/descriptors/example7.descriptor new file mode 100644 index 000000000..6729be3af --- /dev/null +++ b/libs/dfi/gtest/descriptors/example7.descriptor @@ -0,0 +1,13 @@ +:header +type=interface +name=calculator +version=1.0.0 +:annotations +classname=org.example.Calculator +:types +StatsResult={DDD[D average min max input} +:methods +add(DD)D=add(#am=handle;PDD#am=pre;TOut=*D;lOut;)N +sub(DD)D=sub(#am=handle;PDD*#am=pre;D)N +sqrt(D)D=sqrt(#am=handle;PD*#am=pre;D)N +stats([D)LStatsResult;=stats(#am=handle;P[D#am=out;TOut=*LStatsResult;;lOut;)N diff --git a/libs/dfi/gtest/src/json_rpc_tests.cpp b/libs/dfi/gtest/src/json_rpc_tests.cpp index 91b6d9315..c2dc1cc6f 100644 --- a/libs/dfi/gtest/src/json_rpc_tests.cpp +++ b/libs/dfi/gtest/src/json_rpc_tests.cpp @@ -336,11 +336,27 @@ extern "C" { tst_serv serv {nullptr, addFailed, nullptr, nullptr, nullptr}; rc = jsonRpc_call(intf, &serv, R"({)", &result); + EXPECT_STREQ("Got json error: string or '}' expected near end of file", celix_err_popLastError()); ASSERT_EQ(1, rc); rc = jsonRpc_call(intf, &serv, R"({"a": [1.0,2.0]})", &result); + EXPECT_STREQ("Error getting method signature", celix_err_popLastError()); ASSERT_EQ(1, rc); + //request missing argument + rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;"})", &result); + EXPECT_STREQ("Error getting arguments array", celix_err_popLastError()); + ASSERT_EQ(1, rc); + + //request non-array argument + rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;", "a": "hello"})", &result); + EXPECT_STREQ("Error getting arguments array", celix_err_popLastError()); + ASSERT_EQ(1, rc); + + // argument number mismatch + //rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;", "a": []})", &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); @@ -480,6 +496,7 @@ extern "C" { rc = jsonRpc_call(intf, &serv, R"({"m":"unknown", "a": [1.0,2.0]})", &result); ASSERT_EQ(1, rc); + EXPECT_STREQ("Cannot find method with sig 'unknown'", celix_err_popLastError()); dynInterface_destroy(intf); } @@ -785,6 +802,7 @@ class JsonRpcTests : public ::testing::Test { } ~JsonRpcTests() override { + celix_err_resetErrors(); } }; @@ -817,6 +835,25 @@ TEST_F(JsonRpcTests, handleTestOut) { handleTestOut(); } +TEST_F(JsonRpcTests, callPreReference) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example7.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, add, 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, "3.0") != nullptr); + + free(result); + dynInterface_destroy(intf); +} + TEST_F(JsonRpcTests, callPre) { callTestPreAllocated(); } @@ -829,6 +866,25 @@ TEST_F(JsonRpcTests, callOut) { callTestOutput(); } +TEST_F(JsonRpcTests, callOutReference) { + dyn_interface_type *intf = nullptr; + FILE *desc = fopen("descriptors/example7.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, nullptr, nullptr, nullptr, stats}; + + rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;", "a": [[1.0,2.0]]})", &result); + ASSERT_EQ(0, rc); + ASSERT_TRUE(strstr(result, "1.5") != nullptr); + + free(result); + dynInterface_destroy(intf); +} + TEST_F(JsonRpcTests, callTestInvalidRequest) { callTestInvalidRequest(); } diff --git a/libs/dfi/include/json_rpc.h b/libs/dfi/include/json_rpc.h index cdbf3fc33..77e8c434e 100644 --- a/libs/dfi/include/json_rpc.h +++ b/libs/dfi/include/json_rpc.h @@ -44,7 +44,7 @@ extern "C" { * @return 0 if successful, otherwise 1. * */ -CELIX_DFI_EXPORT int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, char **out); +CELIX_DFI_EXPORT int jsonRpc_call(const dyn_interface_type* intf, void* service, const char* request, char** out); /** * @brief Prepare a JSON-RPC request for a given function. @@ -60,7 +60,7 @@ CELIX_DFI_EXPORT int jsonRpc_call(dyn_interface_type *intf, void *service, const * @return 0 if successful, otherwise 1. * */ -CELIX_DFI_EXPORT int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void *args[], char **out); +CELIX_DFI_EXPORT int jsonRpc_prepareInvokeRequest(const dyn_function_type* func, const char* id, void* args[], char** out); /** * @brief Handle a JSON-RPC reply for a given function. @@ -74,7 +74,7 @@ CELIX_DFI_EXPORT int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const * @return 0 if successful, otherwise 1. * */ -CELIX_DFI_EXPORT int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[], int *rsErrno); +CELIX_DFI_EXPORT int jsonRpc_handleReply(const 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 541cd9c3c..08d1a4aa4 100644 --- a/libs/dfi/src/json_rpc.c +++ b/libs/dfi/src/json_rpc.c @@ -26,7 +26,6 @@ #include "celix_err.h" #include -#include #include #include #include @@ -37,289 +36,268 @@ static int ERROR = 1; typedef void (*gen_func_type)(void); struct generic_service_layout { - void *handle; - gen_func_type methods[]; + void* handle; + gen_func_type methods[]; }; -int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, char **out) { - int status = OK; - - const dyn_type* returnType = NULL; - - json_error_t error; - json_t *js_request = json_loads(request, 0, &error); - json_t *arguments = NULL; - const char *sig; - if (js_request) { - if (json_unpack(js_request, "{s:s}", "m", &sig) != 0) { - celix_err_pushf("Got json error '%s'\n", error.text); - json_decref(js_request); - return ERROR; - } else { - arguments = json_object_get(js_request, "a"); - } - } else { - celix_err_pushf("Got json error '%s' for '%s'\n", error.text, request); - return ERROR; - } - - const struct methods_head* methods = dynInterface_methods(intf); - struct method_entry *entry = NULL; - struct method_entry *method = NULL; - TAILQ_FOREACH(entry, methods, entries) { - if (strcmp(sig, entry->id) == 0) { - method = entry; - break; - } - } - - if (method == NULL) { - status = ERROR; +int jsonRpc_call(const dyn_interface_type* intf, void* service, const char* request, char** out) { + int status = OK; + + json_error_t error; + json_auto_t* js_request = json_loads(request, 0, &error); + if (js_request == NULL) { + celix_err_pushf("Got json error: %s", error.text); + return ERROR; + } + json_t* arguments = NULL; + const char* sig; + if (json_unpack(js_request, "{s:s}", "m", &sig) != 0) { + celix_err_push("Error getting method signature"); + return ERROR; + } + arguments = json_object_get(js_request, "a"); + if (arguments == NULL || !json_is_array(arguments)) { + celix_err_push("Error getting arguments array"); + return ERROR; + } + + const struct methods_head* methods = dynInterface_methods(intf); + struct method_entry* entry = NULL; + struct method_entry* method = NULL; + TAILQ_FOREACH(entry, methods, entries) { + if (strcmp(sig, entry->id) == 0) { + method = entry; + break; + } + } + + if (method == NULL) { celix_err_pushf("Cannot find method with sig '%s'", sig); - } - else if (status == OK) { - returnType = dynFunction_returnType(method->dynFunc); - } - - void (*fp)(void) = NULL; - void *handle = NULL; - if (status == OK) { - struct generic_service_layout *serv = service; - handle = serv->handle; - fp = serv->methods[method->index]; - } - - dyn_function_type *func = NULL; - int nrOfArgs = 0; - if (status == OK) { - nrOfArgs = dynFunction_nrOfArguments(entry->dynFunc); - func = entry->dynFunc; - } - - void *args[nrOfArgs]; - - json_t *value = NULL; - - int i; - int index = 0; - - void *ptr = NULL; - void *ptrToPtr = &ptr; - - //setup and deserialize input - for (i = 0; i < nrOfArgs; ++i) { - const dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); - enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); - if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { - value = json_array_get(arguments, index++); - void *outPtr = NULL; + return ERROR; + } + + struct generic_service_layout* serv = service; + void* handle = serv->handle; + void (*fp)(void) = serv->methods[method->index]; + + dyn_function_type* func = method->dynFunc; + int nrOfArgs = dynFunction_nrOfArguments(method->dynFunc); + void* args[nrOfArgs]; + + json_t* value = NULL; + + int i; + int index = 0; + + void* ptr = NULL; + void* ptrToPtr = &ptr; + void* instPtr = NULL; + + //setup and deserialize input + for (i = 0; i < nrOfArgs; ++i) { + const dyn_type* argType = dynType_realType(dynFunction_argumentTypeForIndex(func, i)); + enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); + if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { + value = json_array_get(arguments, index++); + void* outPtr = NULL; status = jsonSerializer_deserializeJson(argType, value, &outPtr); args[i] = outPtr; - } else if (meta == DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT) { - void **instPtr = calloc(1, sizeof(void*)); - void *inst = NULL; - const dyn_type *subType = dynType_typedPointer_getTypedType(argType); + } else if (meta == DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT) { + void* inst = NULL; + const dyn_type *subType = dynType_typedPointer_getTypedType(argType); dynType_alloc(subType, &inst); - *instPtr = inst; - args[i] = instPtr; - } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { - args[i] = &ptrToPtr; - } else if (meta == DYN_FUNCTION_ARGUMENT_META__HANDLE) { - args[i] = &handle; - } - - if (status != OK) { - break; - } - } - json_decref(js_request); - - if (status == OK) { - if (dynType_descriptorType(returnType) != 'N') { - //NOTE To be able to handle exception only N as returnType is supported - celix_err_pushf("Only interface methods with a native int are supported. Found type '%c'", (char)dynType_descriptorType(returnType)); - status = ERROR; - } - } - - ffi_sarg returnVal = 1; - - if (status == OK) { - status = dynFunction_call(func, fp, (void *) &returnVal, args); - } - - int funcCallStatus = (int)returnVal; + instPtr = inst; + args[i] = &instPtr; + } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { + args[i] = &ptrToPtr; + } else if (meta == DYN_FUNCTION_ARGUMENT_META__HANDLE) { + args[i] = &handle; + } + + if (status != OK) { + break; + } + } + json_decref(celix_steal_ptr(js_request)); + + ffi_sarg returnVal = 1; + + if (status == OK) { + status = dynFunction_call(func, fp, (void *) &returnVal, args); + } + + int funcCallStatus = (int)returnVal; //free input args - json_t *jsonResult = NULL; - for(i = 0; i < nrOfArgs; ++i) { - const dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); - enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); - if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { - if (dynType_descriptorType(argType) == 't') { - const char* isConst = dynType_getMetaInfo(argType, "const"); - if (isConst != NULL && strncmp("true", isConst, 5) == 0) { - dynType_free(argType, args[i]); - } else { + json_t* jsonResult = NULL; + for(i = 0; i < nrOfArgs; ++i) { + const dyn_type* argType = dynFunction_argumentTypeForIndex(func, i); + enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); + if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { + if (dynType_descriptorType(argType) == 't') { + const char* isConst = dynType_getMetaInfo(argType, "const"); + if (isConst != NULL && strncmp("true", isConst, 5) == 0) { + dynType_free(argType, args[i]); + } else { //char* -> callee is now owner, no free for char seq needed //will free the actual pointer free(args[i]); - } - } else { + } + } else { dynType_free(argType, args[i]); } - } - } - - //serialize and free output - for (i = 0; i < nrOfArgs; i += 1) { - const 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); - } - const dyn_type* subType = dynType_typedPointer_getTypedType(argType); - void **ptrToInst = (void**)args[i]; - dynType_free(subType, *ptrToInst); - free(ptrToInst); - } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { - if (funcCallStatus == 0 && ptr != NULL) { - const dyn_type *typedType = NULL; - if (status == OK) { + } + } + + //serialize and free output + for (i = 0; i < nrOfArgs; i += 1) { + const dyn_type* argType = dynType_realType(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); + } + const dyn_type* subType = dynType_typedPointer_getTypedType(argType); + void** ptrToInst = (void**)args[i]; + dynType_free(subType, *ptrToInst); + } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { + if (funcCallStatus == 0 && ptr != NULL) { + const dyn_type* typedType = NULL; + if (status == OK) { typedType = dynType_typedPointer_getTypedType(argType); - } - if (status == OK && dynType_descriptorType(typedType) == 't') { - status = jsonSerializer_serializeJson(typedType, (void*) &ptr, &jsonResult); - free(ptr); - } else { - const dyn_type *typedTypedType = NULL; - if (status == OK) { + } + if (status == OK && dynType_descriptorType(typedType) == 't') { + status = jsonSerializer_serializeJson(typedType, (void*) &ptr, &jsonResult); + free(ptr); + } else { + const dyn_type* typedTypedType = NULL; + if (status == OK) { typedTypedType = dynType_typedPointer_getTypedType(typedType); - } - - if(status == OK){ - status = jsonSerializer_serializeJson(typedTypedType, ptr, &jsonResult); - } - - if (status == OK) { - dynType_free(typedTypedType, ptr); - } - } - - } - } - - if (status != OK) { - break; - } - } - - char *response = NULL; - if (status == OK) { - json_t *payload = json_object(); - if (funcCallStatus == 0) { - if (jsonResult == NULL) { - //ignore -> no result - } else { + } + + if(status == OK){ + status = jsonSerializer_serializeJson(typedTypedType, ptr, &jsonResult); + } + + if (status == OK) { + dynType_free(typedTypedType, ptr); + } + } + + } + } + + if (status != OK) { + break; + } + } + + char* response = NULL; + if (status == OK) { + json_t* payload = json_object(); + if (funcCallStatus == 0) { + if (jsonResult == NULL) { + //ignore -> no result + } else { json_object_set_new_nocheck(payload, "r", jsonResult); - } - } else { + } + } else { json_object_set_new_nocheck(payload, "e", json_integer(funcCallStatus)); - } - 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); - } - - if (status == OK) { - *out = response; - } else { - free(response); - } - - return status; + } + //use JSON_COMPACT to reduce the size of the JSON string. + response = json_dumps(payload, JSON_COMPACT | JSON_ENCODE_ANY); + json_decref(payload); + } + + if (status == OK) { + *out = response; + } else { + free(response); + } + + return status; } -int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void *args[], char **out) { - int status = OK; +int jsonRpc_prepareInvokeRequest(const dyn_function_type* func, const char* id, void* args[], char** out) { + int status = OK; - json_t *invoke = json_object(); + json_t* invoke = json_object(); json_object_set_new_nocheck(invoke, "m", json_string(id)); - json_t *arguments = json_array(); + json_t* arguments = json_array(); json_object_set_new_nocheck(invoke, "a", arguments); - int i; - int nrOfArgs = dynFunction_nrOfArguments(func); - for (i = 0; i < nrOfArgs; i +=1) { - const dyn_type *type = dynFunction_argumentTypeForIndex(func, i); - enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); - if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { - json_t *val = NULL; + int i; + int nrOfArgs = dynFunction_nrOfArguments(func); + for (i = 0; i < nrOfArgs; i +=1) { + const dyn_type* type = dynFunction_argumentTypeForIndex(func, i); + enum dyn_function_argument_meta meta = dynFunction_argumentMetaForIndex(func, i); + if (meta == DYN_FUNCTION_ARGUMENT_META__STD) { + json_t* val = NULL; - int rc = jsonSerializer_serializeJson(type, args[i], &val); + int rc = jsonSerializer_serializeJson(type, args[i], &val); if (dynType_descriptorType(type) == 't') { - const char *metaArgument = dynType_getMetaInfo(type, "const"); + const char* metaArgument = dynType_getMetaInfo(type, "const"); if (metaArgument != NULL && strncmp("true", metaArgument, 5) == 0) { //const char * as input -> nop } else { - char **str = args[i]; + char** str = args[i]; free(*str); //char * as input -> got ownership -> free it. } } - if (rc == 0) { - json_array_append_new(arguments, val); - } else { + if (rc == 0) { + json_array_append_new(arguments, val); + } else { celix_err_pushf("Failed to serialize args for function '%s'\n", id); - status = ERROR; - break; - } - } else { - //skip handle / output types - } - } - - 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 { + status = ERROR; + break; + } + } else { + //skip handle / output types + } + } + + 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; + return status; } -int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[], int *rsErrno) { - int status = OK; +int jsonRpc_handleReply(const dyn_function_type* func, const char* reply, void* args[], int* rsErrno) { + int status = OK; - json_error_t error; - json_t *replyJson = json_loads(reply, JSON_DECODE_ANY, &error); - if (replyJson == NULL) { - status = ERROR; + json_error_t error; + json_t* replyJson = json_loads(reply, JSON_DECODE_ANY, &error); + if (replyJson == NULL) { + status = ERROR; celix_err_pushf("Error parsing json '%s', got error '%s'", reply, error.text); - } + } - json_t *result = NULL; - json_t *rsError = NULL; + json_t* result = NULL; + json_t* rsError = NULL; bool replyHasError = false; - if (status == OK) { - *rsErrno = 0; - result = json_object_get(replyJson, "r"); - if (result == NULL) { - rsError = json_object_get(replyJson, "e"); - if(rsError != NULL) { - //get the invocation error of remote service function - *rsErrno = (int)json_integer_value(rsError); + if (status == OK) { + *rsErrno = 0; + result = json_object_get(replyJson, "r"); + if (result == NULL) { + rsError = json_object_get(replyJson, "e"); + if(rsError != NULL) { + //get the invocation error of remote service function + *rsErrno = (int)json_integer_value(rsError); replyHasError = true; - } - } - } + } + } + } int nrOfOutputArgs = 0; int nrOfArgs = dynFunction_nrOfArguments(func); @@ -340,55 +318,55 @@ int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[] } } - if (status == OK && !replyHasError) { + if (status == OK && !replyHasError) { int i; - for (i = 0; i < nrOfArgs; i += 1) { - const 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) { - void *tmp = NULL; - void **out = (void **) args[i]; - size_t size = 0; + for (i = 0; i < nrOfArgs; i += 1) { + const 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) { + void* tmp = NULL; + void** out = (void **) args[i]; + size_t size = 0; if (dynType_descriptorType(argType) == 't') { - status = jsonSerializer_deserializeJson(argType, result, &tmp); - if (tmp != NULL) { - size = strnlen(((char *) *(char**) tmp), 1024 * 1024); - memcpy(*out, *(void**) tmp, size); - } - } else { + status = jsonSerializer_deserializeJson(argType, result, &tmp); + if (tmp != NULL) { + size = strnlen(((char *) *(char**) tmp), 1024 * 1024); + memcpy(*out, *(void**) tmp, size); + } + } else { argType = dynType_typedPointer_getTypedType(argType); - status = jsonSerializer_deserializeJson(argType, result, &tmp); - if (tmp != NULL) { - size = dynType_size(argType); - memcpy(*out, tmp, size); - } - } + status = jsonSerializer_deserializeJson(argType, result, &tmp); + if (tmp != NULL) { + size = dynType_size(argType); + memcpy(*out, tmp, size); + } + } - dynType_free(argType, tmp); - } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { - const dyn_type *subType = dynType_typedPointer_getTypedType(argType); + dynType_free(argType, tmp); + } else if (meta == DYN_FUNCTION_ARGUMENT_META__OUTPUT) { + const dyn_type* subType = dynType_typedPointer_getTypedType(argType); if (dynType_descriptorType(subType) == 't') { - char ***out = (char ***) args[i]; - char **ptrToString = NULL; + char*** out = (char ***) args[i]; + char** ptrToString = NULL; status = jsonSerializer_deserializeJson(subType, result, (void**)&ptrToString); - char *s CELIX_UNUSED = *ptrToString; //note for debug + char* s CELIX_UNUSED = *ptrToString; //note for debug free(ptrToString); **out = (void*)s; } else { - const dyn_type *subSubType = dynType_typedPointer_getTypedType(subType); - void ***out = (void ***) args[i]; - status = jsonSerializer_deserializeJson(subSubType, result, *out); - } - } else { - //skip - } - } - } + const dyn_type* subSubType = dynType_typedPointer_getTypedType(subType); + void*** out = (void ***) args[i]; + status = jsonSerializer_deserializeJson(subSubType, result, *out); + } + } else { + //skip + } + } + } - json_decref(replyJson); + json_decref(replyJson); - return status; + return status; }