From 485c2ada136f5759b341395a7395bc8948a5ccf6 Mon Sep 17 00:00:00 2001 From: Amin Ben Romdhane Date: Fri, 24 Jan 2025 15:49:12 +0100 Subject: [PATCH] Example --- libbbfdm-api/dmapi.h | 2 + libbbfdm-api/dmbbf.c | 169 +++++++++++++++++++++++++++++++++++++ libbbfdm-api/dmbbf.h | 1 + libbbfdm-api/dmentry.c | 5 ++ libbbfdm-ubus/bbfdm-ubus.c | 166 ++++++++++++++++++++++++++++++++++++ libbbfdm-ubus/bbfdm-ubus.h | 3 + 6 files changed, 346 insertions(+) diff --git a/libbbfdm-api/dmapi.h b/libbbfdm-api/dmapi.h index fde7636c..48e49ad6 100644 --- a/libbbfdm-api/dmapi.h +++ b/libbbfdm-api/dmapi.h @@ -195,6 +195,7 @@ struct dmctx { unsigned int dm_type; unsigned char inparam_isparam; unsigned char findparam; + unsigned int amin_num_of_ms; char *in_param; char *in_value; @@ -261,6 +262,7 @@ enum browse_type_enum { enum { BBF_GET_VALUE, + BBF_GET_VALUE_ASYNC, BBF_SCHEMA, BBF_INSTANCES, BBF_GET_NAME, diff --git a/libbbfdm-api/dmbbf.c b/libbbfdm-api/dmbbf.c index c3b91bb6..d2331b73 100644 --- a/libbbfdm-api/dmbbf.c +++ b/libbbfdm-api/dmbbf.c @@ -1173,6 +1173,42 @@ static int get_ubus_value(struct dmctx *dmctx, struct dmnode *node) return 0; } +static int get_ubus_value_async(struct dmctx *dmctx, struct dmnode *node) +{ + char *ubus_name = node->obj->checkdep; + char *in_path = (dmctx->in_param[0] == '\0' || rootcmp(dmctx->in_param, "Device") == 0) ? node->current_object : dmctx->in_param; + struct blob_buf blob = {0}; + int timeout = 5000; + + if ((dm_is_micro_service() == false) && ((dmctx->dm_type & node->obj->bbfdm_type) == false)) { + BBF_DEBUG("[%s] Ignore unsupported proto objects [%s], in[%d], datamodel[%d]", __func__, ubus_name, dmctx->dm_type, node->obj->bbfdm_type); + return 0; + } + + if (node->obj->bbfdm_type == BBFDM_CWMP) { + timeout = 10000; + } + + memset(&blob, 0, sizeof(struct blob_buf)); + blob_buf_init(&blob, 0); + + blobmsg_add_string(&blob, "path", in_path); + prepare_optional_table(dmctx, &blob); + + BBF_ERR("UBUS GET: ubus call %s get '{\"path\":\"%s\"}'", ubus_name, in_path); + int res = ubus_call_blob_msg(ubus_name, "get", &blob, timeout, __get_ubus_value, dmctx); + + blob_buf_free(&blob); + + if (res) + return FAULT_9005; + + if (dmctx->faultcode) + return dmctx->faultcode; + + return 0; +} + static void __get_ubus_supported_dm(struct ubus_request *req, int type, struct blob_attr *msg) { struct blob_attr *cur = NULL; @@ -1884,6 +1920,139 @@ int dm_entry_get_value(struct dmctx *dmctx) return (findparam_check && dmctx->findparam) ? 0 : err; } +/* ********** + * get value async + * **********/ +static int get_value_async_obj(DMOBJECT_ARGS) +{ + return 0; +} + +static int get_value_async_param(DMPARAM_ARGS) +{ + if (node->is_ubus_service) { + return get_ubus_value_async(dmctx, node); + } else { + char full_param[MAX_DM_PATH] = {0}; + char *value = dmstrdup(""); + + snprintf(full_param, sizeof(full_param), "%s%s", node->current_object, leaf->parameter); + + (leaf->getvalue)(full_param, dmctx, data, instance, &value); + + if ((leaf->dm_flags & DM_FLAG_SECURE) && (dmctx->dm_type == BBFDM_CWMP)) { + value = dmstrdup(""); + } else if (value && *value) { + if (leaf->dm_flags & DM_FLAG_REFERENCE) { + value = get_value_by_reference(dmctx, value); + } else { + value = check_value_by_type(value, leaf->type); + } + } else { + value = get_default_value_by_type(leaf->type); + } + + fill_blob_param(&dmctx->bb, full_param, value, DMT_TYPE[leaf->type], leaf->dm_flags); + } + + return 0; +} + +static int mobj_get_value_async_in_param(DMOBJECT_ARGS) +{ + return 0; +} +static int mparam_get_value_async_in_param(DMPARAM_ARGS) +{ + if (node->is_ubus_service) { + int err = get_ubus_value_async(dmctx, node); + if (err) + return FAULT_9005; + + dmctx->findparam = (dmctx->iswildcard) ? 1 : 0; + dmctx->stop = (dmctx->iswildcard) ? false : true; + } else { + char full_param[MAX_DM_PATH] = {0}; + char *value = dmstrdup(""); + + snprintf(full_param, sizeof(full_param), "%s%s", node->current_object, leaf->parameter); + + if (dmctx->iswildcard) { + if (dm_strcmp_wildcard(dmctx->in_param, full_param) != 0) + return FAULT_9005; + } else { + if (DM_STRCMP(dmctx->in_param, full_param) != 0) + return FAULT_9005; + } + + (leaf->getvalue)(full_param, dmctx, data, instance, &value); + + if ((leaf->dm_flags & DM_FLAG_SECURE) && (dmctx->dm_type == BBFDM_CWMP)) { + value = dmstrdup(""); + } else if (value && *value) { + if (leaf->dm_flags & DM_FLAG_REFERENCE) { + value = get_value_by_reference(dmctx, value); + } else + value = check_value_by_type(value, leaf->type); + } else { + value = get_default_value_by_type(leaf->type); + } + + fill_blob_param(&dmctx->bb, full_param, value, DMT_TYPE[leaf->type], leaf->dm_flags); + + dmctx->findparam = (dmctx->iswildcard) ? 1 : 0; + dmctx->stop = (dmctx->iswildcard) ? false : true; + } + + return 0; +} + +int dm_entry_get_value_async(struct dmctx *dmctx) +{ + int err = 0; + unsigned char findparam_check = 0; + DMOBJ *root = dmctx->dm_entryobj; + DMNODE node = {.current_object = ""}; + unsigned int len = DM_STRLEN(dmctx->in_param); + + if ((len > 2 && dmctx->in_param[len - 1] == '.' && dmctx->in_param[len - 2] == '*') || + (dmctx->in_param[0] == '.' && len == 1)) + return FAULT_9005; + + if (dmctx->in_param[0] == '\0' || rootcmp(dmctx->in_param, root->obj) == 0) { + dmctx->inparam_isparam = 0; + dmctx->method_obj = get_value_obj; + dmctx->method_param = get_value_param; + dmctx->checkobj = NULL; + dmctx->checkleaf = NULL; + dmctx->findparam = 1; + dmctx->stop = 0; + findparam_check = 1; + } else if (dmctx->in_param[len - 1] == '.') { + dmctx->inparam_isparam = 0; + dmctx->findparam = 0; + dmctx->stop = 0; + dmctx->checkobj = (dmctx->iswildcard) ? plugin_obj_wildcard_match : plugin_obj_match; + dmctx->checkleaf = (dmctx->iswildcard) ? plugin_leaf_wildcard_match : plugin_leaf_match; + dmctx->method_obj = get_value_async_obj; + dmctx->method_param = get_value_async_param; + findparam_check = 1; + } else { + dmctx->inparam_isparam = 1; + dmctx->findparam = 0; + dmctx->stop = 0; + dmctx->checkobj = (dmctx->iswildcard) ? plugin_obj_wildcard_match : plugin_obj_match; + dmctx->checkleaf = (dmctx->iswildcard) ? plugin_leaf_wildcard_match : plugin_leaf_match; + dmctx->method_obj = mobj_get_value_async_in_param; + dmctx->method_param = mparam_get_value_async_in_param; + findparam_check = (dmctx->iswildcard) ? 1 : 0; + } + + err = dm_browse(dmctx, &node, root, NULL, NULL); + + return (findparam_check && dmctx->findparam) ? 0 : err; +} + /* ********** * get name * **********/ diff --git a/libbbfdm-api/dmbbf.h b/libbbfdm-api/dmbbf.h index ff4639ec..0aa53e0c 100644 --- a/libbbfdm-api/dmbbf.h +++ b/libbbfdm-api/dmbbf.h @@ -42,6 +42,7 @@ void fill_blob_operate(struct blob_buf *bb, const char *path, const char *data, int string_to_bool(const char *v, bool *b); char *get_value_by_reference(struct dmctx *ctx, char *value); int dm_entry_get_value(struct dmctx *dmctx); +int dm_entry_get_value_async(struct dmctx *dmctx); int dm_entry_get_name(struct dmctx *ctx); int dm_entry_get_supported_dm(struct dmctx *ctx); int dm_entry_get_instances(struct dmctx *ctx); diff --git a/libbbfdm-api/dmentry.c b/libbbfdm-api/dmentry.c index 1a4e7627..d9a0e38e 100644 --- a/libbbfdm-api/dmentry.c +++ b/libbbfdm-api/dmentry.c @@ -204,6 +204,11 @@ int bbf_entry_method(struct dmctx *ctx, int cmd) case BBF_GET_VALUE: fault = dm_entry_get_value(ctx); break; + case BBF_GET_VALUE_ASYNC: + BBF_ERR("ctx->in_param=%s", ctx->in_param); + fault = dm_entry_get_value_async(ctx); + BBF_ERR("fault=%d", fault); + break; case BBF_SCHEMA: fault = dm_entry_get_supported_dm(ctx); break; diff --git a/libbbfdm-ubus/bbfdm-ubus.c b/libbbfdm-ubus/bbfdm-ubus.c index fe414b99..06dd42fe 100644 --- a/libbbfdm-ubus/bbfdm-ubus.c +++ b/libbbfdm-ubus/bbfdm-ubus.c @@ -266,6 +266,171 @@ static int bbfdm_get_handler(struct ubus_context *ctx, struct ubus_object *obj _ return 0; } +static bbfdm_data_t *amin_data = NULL; + +struct request_tracker { + struct ubus_request ubus_req; + struct uloop_timeout timeout; + char object_name[128]; +}; + +static void request_timeout_handler(struct uloop_timeout *t) +{ + struct request_tracker *tracker = container_of(t, struct request_tracker, timeout); + + BBF_ERR("Timeout occurred for object: %s\n", tracker->object_name); + + ubus_abort_request(amin_data->ctx, &tracker->ubus_req); + + // Add a timeout response to the consolidated response + blobmsg_add_string(&amin_data->bb, "timeout", "called"); + + // Decrement the pending request count + amin_data->pending_requests--; + + // Check if all requests are done + if (amin_data->pending_requests == 0) { + BBF_ERR("All requests completed.\n"); + ubus_send_reply(amin_data->ctx, &amin_data->amin_new_req, amin_data->bb.head); + ubus_complete_deferred_request(amin_data->ctx, &amin_data->amin_new_req, UBUS_STATUS_OK); + blob_buf_free(&amin_data->bb); + } + + // Clean up the tracker + FREE(tracker); +} + +static void ubus_result_callback(struct ubus_request *req, int type, struct blob_attr *msg) +{ + struct request_tracker *tracker = container_of(req, struct request_tracker, ubus_req); + + /*if (msg) { + char *result = blobmsg_format_json_indent(msg, true, -1); + BBF_ERR("Response from object %s: %s\n", tracker->object_name, result); + FREE(result); + }*/ + + blobmsg_add_string(&amin_data->bb, "result_callback", "true"); + + // Cancel the timeout for this request + uloop_timeout_cancel(&tracker->timeout); + + // Decrement the pending request count + amin_data->pending_requests--; + + // Check if all requests are done + if (amin_data->pending_requests == 0) { + BBF_ERR("All requests completed."); + ubus_send_reply(amin_data->ctx, &amin_data->amin_new_req, amin_data->bb.head); + ubus_complete_deferred_request(amin_data->ctx, &amin_data->amin_new_req, UBUS_STATUS_OK); + blob_buf_free(&amin_data->bb); + } +} + +static void ubus_request_complete(struct ubus_request *req, int ret) +{ + BBF_ERR("Request completed with status: %d", ret); + struct request_tracker *tracker = container_of(req, struct request_tracker, ubus_req); + + FREE(tracker); +} + +static void invoke_object(const char *object_name) +{ + struct blob_buf req_buf = {0}; + uint32_t id; + + // Look up the object ID + if (ubus_lookup_id(amin_data->ctx, object_name, &id)) { + BBF_ERR("Failed to lookup object: %s", object_name); + return; + } + + memset(&req_buf, 0, sizeof(struct blob_buf)); + blob_buf_init(&req_buf, 0); + + struct request_tracker *tracker = calloc(1, sizeof(struct request_tracker)); + if (!tracker) { + BBF_ERR("Failed to allocate memory for request tracker"); + blob_buf_free(&req_buf); + return; + } + + snprintf(tracker->object_name, sizeof(tracker->object_name), "%s", object_name); + + tracker->timeout.cb = request_timeout_handler; + uloop_timeout_set(&tracker->timeout, 5000); + + // Invoke the method asynchronously + if (ubus_invoke_async(amin_data->ctx, id, "status", req_buf.head, &tracker->ubus_req)) { + BBF_ERR("Failed to invoke method asynchronously for object: %s", object_name); + uloop_timeout_cancel(&tracker->timeout); + free(tracker); + } else { + tracker->ubus_req.data_cb = ubus_result_callback; + tracker->ubus_req.complete_cb = ubus_request_complete; + ubus_complete_request_async(amin_data->ctx, &tracker->ubus_req); + } + + blob_buf_free(&req_buf); +} + +static int bbfdm_get_async_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_GET_MAX]; + + bbfdm_data_t *data = calloc(1, sizeof(bbfdm_data_t)); + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + memset(data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_get_policy, __DM_GET_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (tb[DM_GET_PATH]) { + char *path = blobmsg_get_string(tb[DM_GET_PATH]); + snprintf(data->path, sizeof(data->path), "%s", path); + } else { + return UBUS_STATUS_INVALID_ARGUMENT; + } + + data->ctx = ctx; + data->req = req; + + fill_optional_data(data, tb[DM_GET_OPTIONAL]); + + memset(&data->bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&data->bb, 0); + + blobmsg_add_string(&data->bb, "path", data->path); + + ubus_defer_request(ctx, req, &data->amin_new_req); + + //bbfdm_get_value_async(&data); + + const char *objects[] = { "wifi.dataelements.collector", "wifi.ap.test1_0", "wifi" }; + int num_objects = sizeof(objects) / sizeof(objects[0]); + + data->pending_requests = num_objects; + amin_data = data; + + for (int i = 0; i < num_objects; i++) { + invoke_object(objects[i]); + } + + return 0; +} + static const struct blobmsg_policy dm_schema_policy[] = { [DM_SCHEMA_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, [DM_SCHEMA_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, @@ -735,6 +900,7 @@ static int bbfdm_notify_event(struct ubus_context *ctx, struct ubus_object *obj, static struct ubus_method bbf_methods[] = { UBUS_METHOD("get", bbfdm_get_handler, dm_get_policy), + UBUS_METHOD("get_async", bbfdm_get_async_handler, dm_get_policy), UBUS_METHOD("schema", bbfdm_schema_handler, dm_schema_policy), UBUS_METHOD("instances", bbfdm_instances_handler, dm_instances_policy), UBUS_METHOD("set", bbfdm_set_handler, dm_set_policy), diff --git a/libbbfdm-ubus/bbfdm-ubus.h b/libbbfdm-ubus/bbfdm-ubus.h index 869656dc..78209ab1 100644 --- a/libbbfdm-ubus/bbfdm-ubus.h +++ b/libbbfdm-ubus/bbfdm-ubus.h @@ -48,9 +48,12 @@ struct ev_handler_node { typedef struct bbfdm_data { struct ubus_context *ctx; struct ubus_request_data *req; + struct ubus_request_data amin_new_req; //new struct list_head *plist; struct dmctx bbf_ctx; struct blob_buf bb; + char path[256]; //new + int pending_requests; //new uint8_t depth; bool is_raw; } bbfdm_data_t;