Repository: celix Updated Branches: refs/heads/feature/CELIX-237_rsa-ffi c0d4f75af -> f99de6ed1
CELIX-237: Fixed issue with sequence and removed mem leaks from json_rpc Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/f99de6ed Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/f99de6ed Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/f99de6ed Branch: refs/heads/feature/CELIX-237_rsa-ffi Commit: f99de6ed13f730840d233bb1b87ace041f966631 Parents: c0d4f75 Author: Pepijn Noltes <pepijnnol...@gmail.com> Authored: Mon Sep 7 12:32:45 2015 +0200 Committer: Pepijn Noltes <pepijnnol...@gmail.com> Committed: Mon Sep 7 12:32:45 2015 +0200 ---------------------------------------------------------------------- .../dynamic_function_interface/dyn_function.c | 9 +- .../dynamic_function_interface/dyn_type.c | 6 + .../dynamic_function_interface/json_rpc.c | 93 +++++++++------ .../descriptors/example1.descriptor | 8 +- .../dyn_function_tests.cpp | 45 +++++++- .../json_rpc_tests.cpp | 115 ++++++++++++++++++- 6 files changed, 226 insertions(+), 50 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_function.c ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_function.c b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_function.c index abd27d0..e059078 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_function.c +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_function.c @@ -135,13 +135,11 @@ static int dynFunction_parseDescriptor(dyn_function_type *dynFunc, FILE *descrip } } - if (status == 0) { + if (status == OK) { TAILQ_INSERT_TAIL(&dynFunc->arguments, arg, entries); } else { if (arg != NULL) { - if (arg->name != NULL) { - free(arg->name); - } + free(arg->name); if (arg->type != NULL) { dynType_destroy(arg->type); } @@ -218,8 +216,7 @@ void dynFunction_destroy(dyn_function_type *dynFunc) { } int dynFunction_call(dyn_function_type *dynFunc, void(*fn)(void), void *returnValue, void **argValues) { - //TODO check dynFunc arg - ffi_call(&dynFunc->cif, fn, returnValue, argValues); + ffi_call(&dynFunc->cif, fn, returnValue, argValues); return 0; } http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_type.c ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_type.c b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_type.c index aae7ebc..70f6a7b 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_type.c +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_type.c @@ -443,11 +443,16 @@ static int dynType_parseSequence(FILE *stream, dyn_type *type) { type->descriptor = '['; type->sequence.seqType.elements = seq_types; + type->sequence.seqType.type = FFI_TYPE_STRUCT; + type->sequence.seqType.size = 0; + type->sequence.seqType.alignment = 0; + status = dynType_parseWithStream(stream, NULL, type, NULL, &type->sequence.itemType); if (status == OK) { type->ffiType = &type->sequence.seqType; dynType_prepCif(&type->sequence.seqType); + LOG_DEBUG("seq size is %zu\n", type->ffiType->size); } return status; @@ -513,6 +518,7 @@ static void dynType_clear(dyn_type *type) { if (mEntry != NULL) { free(mEntry->name); free(mEntry->value); + free(mEntry); } mEntry = next; } http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface/json_rpc.c ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/json_rpc.c b/remote_services/remote_service_admin_dfi/dynamic_function_interface/json_rpc.c index 5b49f2b..9acd3fb 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface/json_rpc.c +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/json_rpc.c @@ -5,7 +5,6 @@ #include "json_serializer.h" #include "dyn_type.h" #include "dyn_interface.h" - #include <jansson.h> #include <assert.h> #include <stdint.h> @@ -62,6 +61,8 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c LOG_DEBUG("RSA: found method '%s'\n", entry->id); } + dyn_type *returnType = dynFunction_returnType(method->dynFunc); + void (*fp)(void) = NULL; void *handle = NULL; if (status == OK) { @@ -83,22 +84,19 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c int i; int index = 0; + for (i = 0; i < nrOfArgs; i += 1) { dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); const char *argMeta = dynType_getMetaInfo(argType, "am"); if (argMeta == NULL) { - printf("setting std for %i\n", i); value = json_array_get(arguments, index++); status = jsonSerializer_deserializeJson(argType, value, &(args[i])); } else if (strcmp(argMeta, "pre") == 0) { - printf("setting pre alloc output for %i\n", i); dynType_alloc(argType, &args[i]); - - } else if ( strcmp(argMeta, "out") == 0) { - printf("setting output for %i\n", i); - args[i] = NULL; + } else if (strcmp(argMeta, "out") == 0) { + void *inMemPtr = calloc(1, sizeof(void *)); + args[i] = &inMemPtr; } else if (strcmp(argMeta, "handle") == 0) { - printf("setting handle for %i\n", i); args[i] = &handle; } @@ -108,32 +106,54 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c } json_decref(js_request); + if (dynType_descriptorType(returnType) != 'N') { + //NOTE To be able to handle exception only N as returnType is supported + LOG_ERROR("Only interface methods with a native int are supported. Found type '%c'", (char)dynType_descriptorType(returnType)); + status = ERROR; + } + + ffi_sarg returnVal; - //TODO assert return type is native int - int returnVal = 0; - dynFunction_call(func, fp, (void *)&returnVal, args); - printf("done calling\n"); - double **r = args[2]; - printf("result ptrptr is %p, result ptr %p, result is %f\n", r, *r, **r); + if (status == OK) { + dynFunction_call(func, fp, (void *) &returnVal, args); + } + int funcCallStatus = (int)returnVal; + if (funcCallStatus != 0) { + LOG_WARNING("Error calling remote endpoint function, got error code %i", funcCallStatus); + } json_t *jsonResult = NULL; - for (i = 0; i < nrOfArgs; i += 1) { - dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); - const char *argMeta = dynType_getMetaInfo(argType, "am"); - if (argMeta == NULL) { - //ignore - } else if (strcmp(argMeta, "pre") == 0) { - if (status == OK) { - status = jsonSerializer_serializeJson(argType, args[i], &jsonResult); + if (funcCallStatus == 0 && status == OK) { + for (i = 0; i < nrOfArgs; i += 1) { + dyn_type *argType = dynFunction_argumentTypeForIndex(func, i); + const char *argMeta = dynType_getMetaInfo(argType, "am"); + if (argMeta == NULL) { + dynType_free(argType, args[i]); + } else if (strcmp(argMeta, "pre") == 0) { + if (status == OK) { + status = jsonSerializer_serializeJson(argType, args[i], &jsonResult); + } + dynType_free(argType, args[i]); + } else if (strcmp(argMeta, "out") == 0) { + void ***out = args[i]; + if (out != NULL && *out != NULL && **out != NULL) { + status = jsonSerializer_serializeJson(argType, out, &jsonResult); + dyn_type *typedType = NULL; + if (status == OK) { + status = dynType_typedPointer_getTypedType(argType, &typedType); + } + if (status == OK) { + dynType_free(typedType, *out); + } + } else { + LOG_DEBUG("Output ptr is null"); + } } - } else if (strcmp(argMeta, "out") == 0) { - printf("TODO\n"); - assert(false); - } - if (status != OK) { - break; + if (status != OK) { + break; + } } } @@ -141,18 +161,22 @@ int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, c if (status == OK) { LOG_DEBUG("creating payload\n"); json_t *payload = json_object(); - json_object_set_new(payload, "r", jsonResult); + if (funcCallStatus == 0) { + LOG_DEBUG("Setting result payload"); + json_object_set_new(payload, "r", jsonResult); + } else { + LOG_DEBUG("Setting error payload"); + json_object_set_new(payload, "e", json_integer(funcCallStatus)); + } response = json_dumps(payload, JSON_DECODE_ANY); json_decref(payload); - LOG_DEBUG("status ptr is %p. response if '%s'\n", status, response); + LOG_DEBUG("status ptr is %p. response is '%s'\n", status, response); } if (status == OK) { *out = response; } else { - if (response != NULL) { - free(response); - } + free(response); } //TODO free args (created by jsonSerializer and dynType_alloc) (dynType_free) @@ -165,7 +189,7 @@ int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void * LOG_DEBUG("Calling remote function '%s'\n", id); json_t *invoke = json_object(); - json_object_set(invoke, "m", json_string(id)); + json_object_set_new(invoke, "m", json_string(id)); json_t *arguments = json_array(); json_object_set_new(invoke, "a", arguments); @@ -216,7 +240,6 @@ int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[] if (argMeta == NULL) { //skip } else if (strcmp(argMeta, "pre") == 0) { - LOG_DEBUG("found pre argument at %i", i); dyn_type *subType = NULL; dynType_typedPointer_getTypedType(argType, &subType); void *tmp = NULL; http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/example1.descriptor ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/example1.descriptor b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/example1.descriptor index 97b1df8..771dc5e 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/example1.descriptor +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/example1.descriptor @@ -7,7 +7,7 @@ classname=org.example.Calculator :types StatsResult={DDD[D average min max input} :methods -add(DD)D=add(PDD*D)N -sub(DD)D=sub(PDD*D)N -sqrt(D)D=sqrt(PD*D)N -stats([D)LStatsResult;=stats(P[D*LStatsResult;)N +add(DD)D=add(#am=handle;PDD#am=pre;*D)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;*LStatsResult;)N http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_function_tests.cpp ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_function_tests.cpp b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_function_tests.cpp index 413f6e9..14f2f54 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_function_tests.cpp +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_function_tests.cpp @@ -166,6 +166,45 @@ extern "C" { dynFunction_destroy(dynFunc); } + + struct tst_seq { + uint32_t cap; + uint32_t len; + double *buf; + }; + + #define EXAMPLE4_DESCRIPTOR "example([D)V" + + static void example4Func(struct tst_seq seq) { + CHECK_EQUAL(4, seq.cap); + CHECK_EQUAL(2, seq.len); + CHECK_EQUAL(1.1, seq.buf[0]); + CHECK_EQUAL(2.2, seq.buf[1]); + } + + static void test_example4(void) { + dyn_function_type *dynFunc = NULL; + void (*fp)(void) = (void(*)(void)) example4Func; + int rc; + + rc = dynFunction_parseWithStr(EXAMPLE4_DESCRIPTOR, NULL, &dynFunc); + CHECK_EQUAL(0, rc); + + double buf[4]; + buf[0] = 1.1; + buf[1] = 2.2; + struct tst_seq seq; + seq.cap = 4; + seq.len = 2; + seq.buf = buf; + + void *args[1]; + args[0] = &seq; + rc = dynFunction_call(dynFunc, fp, NULL, args); + CHECK_EQUAL(0, rc); + + dynFunction_destroy(dynFunc); + } } TEST_GROUP(DynFunctionTests) { @@ -190,4 +229,8 @@ TEST(DynFunctionTests, DynFuncAccTest) { TEST(DynFunctionTests, DynFuncTest3) { test_example3(); -} \ No newline at end of file +} + +TEST(DynFunctionTests, DynFuncTest4) { + test_example4(); +} http://git-wip-us.apache.org/repos/asf/celix/blob/f99de6ed/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/json_rpc_tests.cpp ---------------------------------------------------------------------- diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/json_rpc_tests.cpp b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/json_rpc_tests.cpp index 60b028f..5e116a5 100644 --- a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/json_rpc_tests.cpp +++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/json_rpc_tests.cpp @@ -2,6 +2,8 @@ * Licensed under Apache License v2. See LICENSE for more information. */ #include <CppUTest/TestHarness.h> +#include <float.h> +#include <assert.h> #include "CppUTest/CommandLineTestRunner.h" extern "C" { @@ -74,9 +76,110 @@ static void stdLog(void *handle, int level, const char *file, int line, const ch dynFunction_destroy(dynFunc); } + int add(void *handle, double a, double b, double *result) { + *result = a + b; + return 0; + } + + struct tst_seq { + uint32_t cap; + uint32_t len; + double *buf; + }; + + + //StatsResult={DDD[D average min max input} + struct tst_StatsResult { + double average; + double min; + double max; + struct tst_seq input; + }; + + + int stats(void *handle, struct tst_seq input, struct tst_StatsResult **out) { + assert(out != NULL); + assert(*out == NULL); + double total = 0.0; + int count = 0; + double max = DBL_MIN; + double min = DBL_MAX; + + int i; + for (i = 0; i<input.len; i += 1) { + total += input.buf[i]; + count += 1; + if (input.buf[i] > max) { + max = input.buf[i]; + } + if (input.buf[i] < min) { + min = input.buf[i]; + } + } + + struct tst_StatsResult *result = (struct tst_StatsResult *) calloc(1, sizeof(*result)); + result->average = total / count; + result->min = min; + result->max = max; + double *buf = (double *)calloc(input.len, sizeof(double)); + memcpy(buf, input.buf, input.len * sizeof(double)); + result->input.len = input.len; + result->input.cap = input.len; + result->input.buf = buf; + + *out = result; + return 0; + } + + struct tst_serv { + void *handle; + int (*add)(void *, double, double, double *); + int (*sub)(void *, double, double, double *); + int (*sqrt)(void *, double, double *); + int (*stats)(void *, struct tst_seq, struct tst_StatsResult **); + }; + + void callTestPreAllocated(void) { + dyn_interface_type *intf = NULL; + FILE *desc = fopen("descriptors/example1.descriptor", "r"); + CHECK(desc != NULL); + int rc = dynInterface_parse(desc, &intf); + CHECK_EQUAL(0, rc); + + char *result = NULL; + + struct tst_serv serv; + serv.handle = NULL; + serv.add = add; + + + rc = jsonRpc_call(intf, &serv, "{\"m\":\"add(DD)D\", \"a\": [1.0,2.0]}", &result); + CHECK_EQUAL(0, rc); + STRCMP_CONTAINS("3.0", result); + + free(result); + dynInterface_destroy(intf); + } + + void callTestOutput(void) { + dyn_interface_type *intf = NULL; + FILE *desc = fopen("descriptors/example1.descriptor", "r"); + CHECK(desc != NULL); + int rc = dynInterface_parse(desc, &intf); + CHECK_EQUAL(0, rc); + + char *result = NULL; - void callTest(void) { - //TODO + struct tst_serv serv; + serv.handle = NULL; + serv.stats = stats; + + rc = jsonRpc_call(intf, &serv, "{\"m\":\"stats([D)LStatsResult;\", \"a\": [[1.0,2.0]]}", &result); + CHECK_EQUAL(0, rc); + STRCMP_CONTAINS("1.5", result); //avg + + free(result); + dynInterface_destroy(intf); } } @@ -103,8 +206,12 @@ TEST(JsonRpcTests, handleTest) { handleTest(); } -TEST(JsonRpcTests, call) { - callTest(); +TEST(JsonRpcTests, callPre) { + callTestPreAllocated(); +} + +TEST(JsonRpcTests, callOut) { + callTestOutput(); }