From 556ac3404ded8217f890cc5e61aff5811b81a840 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 15 Mar 2017 11:45:19 -0700 Subject: [ocf] register resource correctly (#800) Signed-off-by: James Prestwood --- samples/OcfServer.js | 2 +- src/zjs_modules.c | 2 +- src/zjs_ocf_client.c | 35 ++++++-- src/zjs_ocf_client.h | 5 ++ src/zjs_ocf_common.c | 20 +++++ src/zjs_ocf_common.h | 13 +++ src/zjs_ocf_server.c | 229 +++++++++++++++++++++++++++++++++++++++------------ src/zjs_ocf_server.h | 12 +++ 8 files changed, 254 insertions(+), 64 deletions(-) diff --git a/samples/OcfServer.js b/samples/OcfServer.js index 33b4013..eb2d3ef 100644 --- a/samples/OcfServer.js +++ b/samples/OcfServer.js @@ -39,7 +39,7 @@ var resourceInit = { var MyResource = null; server.register(resourceInit).then(function(resource) { - console.log("Registered resource"); + console.log("Registered resource. UUID: " + ocf.device.uuid); MyResource = resource; server.on("retrieve", function(request, observe) { MyProperties.state = (MyProperties.state) ? false : true; diff --git a/src/zjs_modules.c b/src/zjs_modules.c index 41b3262..c89b2cb 100644 --- a/src/zjs_modules.c +++ b/src/zjs_modules.c @@ -110,7 +110,7 @@ module_t zjs_modules_array[] = { { "performance", zjs_performance_init }, #endif #ifdef BUILD_MODULE_OCF - { "ocf", zjs_ocf_init }, + { "ocf", zjs_ocf_init, zjs_ocf_cleanup }, #endif #ifdef BUILD_MODULE_TEST_PROMISE { "test_promise", zjs_test_promise_init } diff --git a/src/zjs_ocf_client.c b/src/zjs_ocf_client.c index b6a822f..2add8c2 100644 --- a/src/zjs_ocf_client.c +++ b/src/zjs_ocf_client.c @@ -49,7 +49,7 @@ struct ocf_handler { struct client_resource* res; }; -struct client_resource* resources = NULL; +static struct client_resource* resource_list = NULL; #define MAX_URI_LENGTH (30) @@ -216,7 +216,7 @@ static void print_props_data(oc_client_response_t *data) static struct client_resource* find_resource_by_id(const char* device_id) { if (device_id) { - struct client_resource* cur = resources; + struct client_resource* cur = resource_list; while (cur) { if (cur->state != RES_STATE_SEARCHING) { if (strcmp(cur->device_id, device_id) == 0) { @@ -236,7 +236,7 @@ static struct client_resource* find_resource_by_id(const char* device_id) static struct client_resource* find_resource_by_path(const char* path) { if (path) { - struct client_resource* cur = resources; + struct client_resource* cur = resource_list; while (cur) { if (cur->state != RES_STATE_SEARCHING) { if (strcmp(cur->resource_path, path) == 0) { @@ -273,7 +273,7 @@ static void free_client(const uintptr_t native_p) { struct client_resource* client = (struct client_resource*)native_p; if (client) { - struct client_resource* cur = resources; + struct client_resource* cur = resource_list; while (cur->next) { if (cur->next == client) { cur->next = client->next; @@ -295,7 +295,7 @@ static void free_client(const uintptr_t native_p) } /* - * Add a discovered resource to the list of resources + * Add a discovered resource to the list of resource_list */ static void add_resource(char* id, char* type, char* path, jerry_value_t client, jerry_value_t listener) { @@ -328,8 +328,8 @@ static void add_resource(char* id, char* type, char* path, jerry_value_t client, zjs_add_event_listener(new->client, "resourcefound", listener); } - new->next = resources; - resources = new; + new->next = resource_list; + resource_list = new; } static void post_ocf_promise(void* handle) @@ -377,7 +377,7 @@ static oc_discovery_flags_t discovery(const char *di, for (i = 0; i < oc_string_array_get_allocated_size(types); i++) { char *t = oc_string_array_get_item(types, i); - struct client_resource* cur = resources; + struct client_resource* cur = resource_list; while (cur) { if (cur->state == RES_STATE_SEARCHING) { // check if resource has any filter constraints @@ -1080,4 +1080,23 @@ jerry_value_t zjs_ocf_client_init() return ocf_client; } +void zjs_ocf_client_cleanup() +{ + if (resource_list) { + struct client_resource *cur = resource_list; + while (cur) { + if (cur->resource_type) { + zjs_free(cur->resource_type); + } + if (cur->resource_path) { + zjs_free(cur->resource_path); + } + jerry_release_value(cur->client); + resource_list = resource_list->next; + zjs_free(cur); + cur = resource_list; + } + } +} + #endif // BUILD_MODULE_OCF diff --git a/src/zjs_ocf_client.h b/src/zjs_ocf_client.h index 6f78d1a..0ac1ac0 100644 --- a/src/zjs_ocf_client.h +++ b/src/zjs_ocf_client.h @@ -10,4 +10,9 @@ */ jerry_value_t zjs_ocf_client_init(); +/* + * Cleanup OCF client + */ +void zjs_ocf_client_cleanup(); + #endif // __zjs_ocf_client__ diff --git a/src/zjs_ocf_common.c b/src/zjs_ocf_common.c index 86c1eb8..9e4f6b7 100644 --- a/src/zjs_ocf_common.c +++ b/src/zjs_ocf_common.c @@ -210,6 +210,15 @@ static void issue_requests(void) #define CONFIG_DEVICE_NAME CONFIG_BLUETOOTH_DEVICE_NAME #endif +void zjs_set_uuid(char* uuid) +{ + jerry_value_t device = zjs_get_property(ocf_object, "device"); + if (!jerry_value_is_undefined(device)) { + zjs_obj_add_string(device, uuid, "uuid"); + } + jerry_release_value(device); +} + static void platform_init(void *data) { uint32_t size; @@ -470,4 +479,15 @@ jerry_value_t zjs_ocf_init() return ocf_object; } +void zjs_ocf_cleanup() +{ +#ifdef OC_SERVER + zjs_ocf_server_cleanup(); +#endif +#ifdef OC_CLIENT + zjs_ocf_client_cleanup(); +#endif + jerry_release_value(ocf_object); +} + #endif // BUILD_MODULE_OCF diff --git a/src/zjs_ocf_common.h b/src/zjs_ocf_common.h index 99e0c7f..e3847e8 100644 --- a/src/zjs_ocf_common.h +++ b/src/zjs_ocf_common.h @@ -79,6 +79,14 @@ void zjs_ocf_free_props(void* h); */ uint8_t main_poll_routine(void* handle); +/** + * Set the 'uuid' property in the device object. This API is required because + * we dont get the UUID until after the device object is created/initialized. + * + * @param uuid UUID obtained from iotivity-constrained system + */ +void zjs_set_uuid(char* uuid); + /* * Start Iotivity-constrained. */ @@ -88,3 +96,8 @@ int zjs_ocf_start(); * Object returned from require('ocf') */ jerry_value_t zjs_ocf_init(); + +/* + * Cleanup for OCF object + */ +void zjs_ocf_cleanup(); diff --git a/src/zjs_ocf_server.c b/src/zjs_ocf_server.c index 0a4f8ae..cc7c879 100644 --- a/src/zjs_ocf_server.c +++ b/src/zjs_ocf_server.c @@ -23,12 +23,22 @@ struct server_resource { * 'this' pointer so we have to save it in C. */ jerry_value_t object; - char* device_id; - char* resource_path; uint32_t error_code; oc_resource_t *res; + char* device_id; + char* resource_path; + uint8_t num_types; + char** resource_types; + uint8_t num_ifaces; + char** resource_ifaces; + uint8_t flags; }; +typedef struct resource_list { + struct server_resource* resource; + struct resource_list* next; +} resource_list_t; + struct ocf_response { oc_method_t method; // Current method being executed oc_request_t* request; @@ -41,6 +51,8 @@ struct ocf_handler { struct server_resource* res; }; +static resource_list_t* res_list = NULL; + #define FLAG_OBSERVE 1 << 0 #define FLAG_DISCOVERABLE 1 << 1 #define FLAG_SLOW 1 << 2 @@ -392,14 +404,15 @@ static jerry_value_t ocf_notify(const jerry_value_t function_val, } /* -typedef struct resource_list { - oc_resource_t *resource; - struct resource_list* next; -} resource_list_t; - -static resource_list_t *r_list = NULL; -static bool has_registered = false; -*/ + * TODO: This is a workaround for getting the resource UUID. There is no API + * available to do this currently so we must get it with this external + * structure. + */ +extern struct +{ + oc_uuid_t uuid; + oc_string_t payload; +} oc_device_info[OC_MAX_NUM_DEVICES]; static jerry_value_t ocf_register(const jerry_value_t function_val, const jerry_value_t this, @@ -412,11 +425,12 @@ static jerry_value_t ocf_register(const jerry_value_t function_val, struct server_resource* resource; int i; jerry_value_t promise = jerry_create_object(); - struct ocf_handler* h; + struct ocf_handler* h = NULL; // Required jerry_value_t resource_path_val = zjs_get_property(argv[0], "resourcePath"); if (!jerry_value_is_string(resource_path_val)) { + jerry_release_value(resource_path_val); ERR_PRINT("resourcePath not found\n"); REJECT(promise, "TypeMismatchError", "resourcePath not found", h); return promise; @@ -426,14 +440,14 @@ static jerry_value_t ocf_register(const jerry_value_t function_val, jerry_value_t res_type_array = zjs_get_property(argv[0], "resourceTypes"); if (!jerry_value_is_array(res_type_array)) { + jerry_release_value(res_type_array); ERR_PRINT("resourceTypes array not found\n"); REJECT(promise, "TypeMismatchError", "resourceTypes array not found", h); return promise; } - uint32_t num_types = jerry_get_array_length(res_type_array); // Optional - uint32_t flags = 0; + uint8_t flags = 0; jerry_value_t observable_val = zjs_get_property(argv[0], "observable"); if (jerry_value_is_boolean(observable_val)) { if (jerry_get_boolean_value(observable_val)) { @@ -466,47 +480,86 @@ static jerry_value_t ocf_register(const jerry_value_t function_val, } jerry_release_value(secure_val); + resource_list_t* new = zjs_malloc(sizeof(resource_list_t)); + if (!new) { + jerry_release_value(res_type_array); + REJECT(promise, "InternalError", "Could not allocate resource list", h); + return promise; + } resource = new_server_resource(resource_path); - - if (zjs_ocf_start() < 0) { - REJECT(promise, "InternalError", "OCF failed to start", h); + if (!resource) { + jerry_release_value(res_type_array); + REJECT(promise, "InternalError", "Could not allocate resource", h); return promise; } + new->resource = resource; + new->next = res_list; + res_list = new; - resource->res = oc_new_resource(resource_path, num_types, 0); + resource->flags = flags; + + resource->num_types = jerry_get_array_length(res_type_array); + resource->resource_types = zjs_malloc(sizeof(char*) * resource->num_types); + if (!resource->resource_types) { + jerry_release_value(res_type_array); + REJECT(promise, "InternalError", "resourceType alloc failed", h); + return promise; + } - for (i = 0; i < num_types; ++i) { + for (i = 0; i < resource->num_types; ++i) { jerry_value_t type_val = jerry_get_property_by_index(res_type_array, i); - ZJS_GET_STRING(type_val, type_name, OCF_MAX_RES_TYPE_LEN); - oc_resource_bind_resource_type(resource->res, type_name); + uint32_t size = OCF_MAX_RES_TYPE_LEN; + resource->resource_types[i] = zjs_alloc_from_jstring(type_val, &size); + if (!resource->resource_types[i]) { + jerry_release_value(res_type_array); + jerry_release_value(type_val); + REJECT(promise, "InternalError", "resourceType alloc failed", h); + return promise; + } jerry_release_value(type_val); } - oc_resource_bind_resource_interface(resource->res, OC_IF_RW); - oc_resource_set_default_interface(resource->res, OC_IF_RW); + jerry_release_value(res_type_array); -#ifdef OC_SECURITY - oc_resource_make_secure(resource->res); -#endif + jerry_value_t iface_array = zjs_get_property(argv[0], "interfaces"); + if (!jerry_value_is_array(iface_array)) { + jerry_release_value(iface_array); + ERR_PRINT("interfaces array not found\n"); + REJECT(promise, "TypeMismatchError", "resourceTypes array not found", h); + return promise; + } - if (flags & FLAG_DISCOVERABLE) { - oc_resource_set_discoverable(resource->res, 1); + resource->num_ifaces = jerry_get_array_length(iface_array); + resource->resource_ifaces = zjs_malloc(sizeof(char*) * resource->num_ifaces); + if (!resource->resource_ifaces) { + jerry_release_value(iface_array); + REJECT(promise, "InternalError", "interfaces alloc failed", h); + return promise; } - if (flags & FLAG_OBSERVE) { - oc_resource_set_periodic_observable(resource->res, 1); + + for (i = 0; i < resource->num_ifaces; ++i) { + jerry_value_t val = jerry_get_property_by_index(iface_array, i); + uint32_t size = OCF_MAX_RES_TYPE_LEN; + resource->resource_ifaces[i] = zjs_alloc_from_jstring(val, &size); + if (!resource->resource_ifaces[i]) { + jerry_release_value(iface_array); + jerry_release_value(val); + REJECT(promise, "InternalError", "resourceType alloc failed", h); + return promise; + } + jerry_release_value(val); } - /* - * TODO: Since requests are handled in JS can POST/PUT use the same handler? - */ - oc_resource_set_request_handler(resource->res, OC_GET, ocf_get_handler, resource); - oc_resource_set_request_handler(resource->res, OC_PUT, ocf_put_handler, resource); - oc_resource_set_request_handler(resource->res, OC_POST, ocf_put_handler, resource); + jerry_release_value(iface_array); - oc_add_resource(resource->res); + // Start OCF. Device/platform/resource properties should all be set after + if (zjs_ocf_start() < 0) { + REJECT(promise, "InternalError", "OCF failed to start", h); + return promise; + } - /*resource_list_t *new = zjs_malloc(sizeof(resource_list_t)); - new->resource = resource->res; - new->next = r_list; - r_list = new;*/ + // Get UUID and set it in the ocf.device object + char uuid[37]; + oc_uuid_to_str(&oc_device_info[resource->res->device].uuid, uuid, 37); + zjs_set_uuid(uuid); h = new_ocf_handler(resource); zjs_make_promise(promise, post_ocf_promise, h); @@ -526,26 +579,56 @@ static jerry_value_t ocf_register(const jerry_value_t function_val, DBG_PRINT("registered resource, path=%s\n", resource_path); - jerry_release_value(res_type_array); - return promise; } -/* - * TODO: iotivity-constrained requires that resources get registered in this - * function, which gets called long before we know about any resources. - * What we have "works" but its not how its supposed to be structured. - */ void zjs_ocf_register_resources(void) { - // ZJS_PRINT("zjs_ocf_register_resources() callback\n"); - /*resource_list_t *cur = r_list; + resource_list_t* cur = res_list; while (cur) { - oc_add_resource(cur->resource); - resource_list_t *next = cur->next; - zjs_free(cur); - cur = next; - }*/ + int i; + struct server_resource* resource = cur->resource; + + resource->res = oc_new_resource(resource->resource_path, resource->num_types, 0); + for (i = 0; i < resource->num_types; ++i) { + oc_resource_bind_resource_type(resource->res, resource->resource_types[i]); + } + for (i = 0; i < resource->num_ifaces; ++i) { + if (strcmp(resource->resource_ifaces[i], "/oic/if/rw") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_RW); + oc_resource_set_default_interface(resource->res, OC_IF_RW); + } else if (strcmp(resource->resource_ifaces[0], "/oic/if/r") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_R); + oc_resource_set_default_interface(resource->res, OC_IF_R); + } else if (strcmp(resource->resource_ifaces[0], "/oic/if/a") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_A); + oc_resource_set_default_interface(resource->res, OC_IF_A); + } else if (strcmp(resource->resource_ifaces[0], "/oic/if/s") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_S); + oc_resource_set_default_interface(resource->res, OC_IF_S); + } else if (strcmp(resource->resource_ifaces[0], "/oic/if/b") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_B); + oc_resource_set_default_interface(resource->res, OC_IF_B); + } else if (strcmp(resource->resource_ifaces[0], "/oic/if/ll") == 0) { + oc_resource_bind_resource_interface(resource->res, OC_IF_LL); + oc_resource_set_default_interface(resource->res, OC_IF_LL); + } + } + if (resource->flags & FLAG_DISCOVERABLE) { + oc_resource_set_discoverable(resource->res, 1); + } + if (resource->flags & FLAG_OBSERVE) { + oc_resource_set_periodic_observable(resource->res, 1); + } + + oc_resource_set_request_handler(resource->res, OC_GET, ocf_get_handler, resource); + oc_resource_set_request_handler(resource->res, OC_PUT, ocf_put_handler, resource); + oc_resource_set_request_handler(resource->res, OC_POST, ocf_put_handler, resource); + + oc_add_resource(resource->res); + + cur = cur->next; + } } jerry_value_t zjs_ocf_server_init() @@ -560,4 +643,42 @@ jerry_value_t zjs_ocf_server_init() return server; } +void zjs_ocf_server_cleanup() +{ + if (res_list) { + resource_list_t* cur = res_list; + while (cur) { + int i; + struct server_resource* resource = cur->resource; + if (resource->device_id) { + zjs_free(resource->device_id); + } + if (resource->resource_path) { + zjs_free(resource->resource_path); + } + if (resource->resource_types) { + for (i = 0; i < resource->num_types; ++i) { + if (resource->resource_types[i]) { + zjs_free(resource->resource_types[i]); + } + } + zjs_free(resource->resource_types); + } + if (resource->resource_ifaces) { + for (i = 0; i < resource->num_ifaces; ++i) { + if (resource->resource_ifaces[i]) { + zjs_free(resource->resource_ifaces[i]); + } + } + zjs_free(resource->resource_ifaces); + } + jerry_release_value(resource->object); + zjs_free(resource); + res_list = res_list->next; + zjs_free(cur); + cur = res_list; + } + } +} + #endif // BUILD_MODULE_OCF diff --git a/src/zjs_ocf_server.h b/src/zjs_ocf_server.h index 291474e..465bab4 100644 --- a/src/zjs_ocf_server.h +++ b/src/zjs_ocf_server.h @@ -3,5 +3,17 @@ #include "zjs_util.h" #include "zjs_common.h" +/* + * Initialize and return OCF server object + */ jerry_value_t zjs_ocf_server_init(); + +/* + * iotivity-constrained callback to register resources. + */ void zjs_ocf_register_resources(void); + +/* + * OCF server module cleanup + */ +void zjs_ocf_server_cleanup(); -- cgit v1.2.3