Store data model schema during service registration

This commit is contained in:
Amin Ben Romdhane 2025-05-21 15:50:18 +00:00 committed by IOPSYS Dev
parent 79a91515e5
commit a20a15888b
No known key found for this signature in database
7 changed files with 216 additions and 62 deletions

View file

@ -27,8 +27,7 @@
extern struct list_head registered_services;
extern int g_log_level;
static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unused)),
struct ubus_event_handler *ev __attribute__((unused)),
static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev __attribute__((unused)),
const char *type, struct blob_attr *msg)
{
const struct blobmsg_policy policy = {
@ -58,19 +57,75 @@ static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unus
service->is_blacklisted = false;
service->consecutive_timeouts = 0;
service_found = true;
fill_service_schema(ctx, 5000, service->name, &service->dm_schema);
BBFDM_ERR("Service '%s' found in registry. Resetting blacklist and timeout counters.", path);
break;
}
}
if (!service_found) {
BBFDM_ERR("Newly registered service '%s' is not recognized in the registry."
" Possible missing configuration JSON file under '%s'.",
path, BBFDM_MICROSERVICE_INPUT_PATH);
}
if (!service_found) {
BBFDM_ERR("Newly registered service '%s' is not recognized in the registry."
" Possible missing configuration JSON file under '%s'.",
path, BBFDM_MICROSERVICE_INPUT_PATH);
}
}
}
static void bbfdm_handle_schema_request(struct ubus_context *ctx, struct ubus_request_data *req,
const char *requested_path, unsigned int requested_proto)
{
struct blob_buf bb = {0};
bool schema_found = false;
int len = strlen(requested_path);
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
void *array = blobmsg_open_array(&bb, "results");
if (len > 0 && requested_path[len - 1] == '.') {
service_entry_t *service = NULL;
list_for_each_entry(service, &registered_services, list) {
if (service->is_blacklisted ||
!service_path_match(requested_path, requested_proto, service) ||
!service->dm_schema)
continue;
struct blob_attr *attr = NULL;
size_t remaining = 0;
const struct blobmsg_policy policy[] = {
{ "path", BLOBMSG_TYPE_STRING },
};
blobmsg_for_each_attr(attr, service->dm_schema->head, remaining) {
struct blob_attr *fields[1];
blobmsg_parse(policy, 1, fields, blobmsg_data(attr), blobmsg_len(attr));
char *path = fields[0] ? blobmsg_get_string(fields[0]) : "";
if (strlen(path) == 0)
continue;
if (strncmp(requested_path, path, len) == 0) {
blobmsg_add_blob(&bb, attr);
schema_found = true;
}
}
}
}
if (!schema_found)
print_fault_message(&bb, requested_path, 7026, "Path is not present in the data model schema");
blobmsg_close_array(&bb, array);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
}
static const struct blobmsg_policy bbfdm_policy[] = {
[BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
@ -83,6 +138,7 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj
struct blob_attr *tb[__BBFDM_MAX];
service_entry_t *service = NULL;
unsigned int requested_proto = BBFDMD_BOTH;
bool raw_format = false;
if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) {
BBFDM_ERR("Failed to parse input message");
@ -94,24 +150,33 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj
return UBUS_STATUS_INVALID_ARGUMENT;
}
struct async_request_context *context = calloc(1, sizeof(struct async_request_context));
char *requested_path = blobmsg_get_string(tb[BBFDM_PATH]);
fill_optional_input(tb[BBFDM_INPUT], &requested_proto, &raw_format);
if (strcmp(method, "schema") == 0 && requested_proto != BBFDMD_CWMP) {
BBFDM_INFO("START: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto);
bbfdm_handle_schema_request(ctx, req, requested_path, requested_proto);
BBFDM_INFO("END: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto);
return 0;
}
struct async_request_context *context = (struct async_request_context *)calloc(1, sizeof(struct async_request_context));
if (!context) {
BBFDM_ERR("Failed to allocate memory");
return UBUS_STATUS_UNKNOWN_ERROR;
}
BBFDM_INFO("START: ubus method|%s|, name|%s|", method, obj->name);
BBFDM_INFO("START: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto);
snprintf(context->requested_path, sizeof(context->requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH]));
snprintf(context->requested_path, sizeof(context->requested_path), "%s", requested_path);
snprintf(context->ubus_method, sizeof(context->ubus_method), "%s", method);
context->ubus_ctx = ctx;
context->raw_format = raw_format;
memset(&context->tmp_bb, 0, sizeof(struct blob_buf));
blob_buf_init(&context->tmp_bb, 0);
fill_optional_input(tb[BBFDM_INPUT], &requested_proto, &context->raw_format);
ubus_defer_request(ctx, req, &context->request_data);
list_for_each_entry(service, &registered_services, list) {
@ -119,7 +184,7 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj
if (service->is_blacklisted)
continue;
if (!is_path_match(context->requested_path, requested_proto, service))
if (!service_path_match(context->requested_path, requested_proto, service))
continue;
run_async_call(context, service, msg);
@ -167,7 +232,7 @@ static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj,
if (service->is_blacklisted)
continue;
if (!is_path_match(requested_path, requested_proto, service))
if (!service_path_match(requested_path, requested_proto, service))
continue;
run_sync_call(service->name, method, msg, &bb);

View file

@ -88,11 +88,40 @@ struct blob_attr *get_results_array(struct blob_attr *msg)
return tb[0];
}
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type)
bool str_match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[])
{
regex_t re;
if (!string || !pattern)
return false;
if (regcomp(&re, pattern, REG_EXTENDED) != 0)
return false;
int status = regexec(&re, string, nmatch, pmatch, 0);
regfree(&re);
return (status != 0) ? false : true;
}
bool proto_match(unsigned int dm_type, const enum bbfdmd_type_enum type)
{
return (dm_type == BBFDMD_BOTH || type == BBFDMD_BOTH || dm_type == type) && type != BBFDMD_NONE;
}
void print_fault_message(struct blob_buf *blob_buf, const char *path, uint32_t fault_code, const char *fault_msg)
{
if (!blob_buf || !path || !fault_msg)
return;
void *table = blobmsg_open_table(blob_buf, NULL);
blobmsg_add_string(blob_buf, "path", path);
blobmsg_add_u32(blob_buf, "fault", fault_code);
blobmsg_add_string(blob_buf, "fault_msg", fault_msg);
blobmsg_close_table(blob_buf, table);
}
static void sync_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *attr = NULL;

View file

@ -12,6 +12,7 @@
#ifndef BBFDMD_COMMON_H
#define BBFDMD_COMMON_H
#include <regex.h>
#include "libbbfdm-api/version-2/bbfdm_api.h"
#define BBFDM_ROOT_OBJECT "Device."
@ -36,7 +37,10 @@ void fill_optional_input(struct blob_attr *msg, unsigned int *proto, bool *raw_f
struct blob_attr *get_results_array(struct blob_attr *msg);
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type);
bool str_match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[]);
bool proto_match(unsigned int dm_type, const enum bbfdmd_type_enum type);
void print_fault_message(struct blob_buf *blob_buf, const char *path, uint32_t fault_code, const char *fault_msg);
void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response);

View file

@ -21,9 +21,11 @@ extern int g_log_level;
static void add_linker_entry(struct async_request_context *ctx, const char *linker_path, const char *linker_value)
{
struct linker_args *linker = calloc(1, sizeof(struct linker_args));
if (!linker)
struct linker_args *linker = (struct linker_args *)calloc(1, sizeof(struct linker_args));
if (!linker) {
BBFDM_ERR("Failed to allocate memory");
return;
}
list_add_tail(&linker->list, &ctx->linker_list);
linker->path = strdup(linker_path ? linker_path : "");
@ -218,11 +220,7 @@ static void prepare_and_send_response(struct async_request_context *ctx)
void *array = blobmsg_open_array(&bb_raw, "results");
if (ctx->path_matched == false) {
void *table = blobmsg_open_table(&bb_raw, NULL);
blobmsg_add_string(&bb_raw, "path", ctx->requested_path);
blobmsg_add_u32(&bb_raw, "fault", 9005);
blobmsg_add_string(&bb_raw, "fault_msg", "Invalid parameter name");
blobmsg_close_table(&bb_raw, table);
print_fault_message(&bb_raw, ctx->requested_path, 9005, "Invalid parameter name");
} else {
blobmsg_for_each_attr(attr, ctx->tmp_bb.head, remaining) {
if (strcmp(ctx->ubus_method, "get") == 0) {
@ -292,7 +290,7 @@ void send_response(struct async_request_context *ctx)
ubus_complete_deferred_request(ctx->ubus_ctx, &ctx->request_data, UBUS_STATUS_OK);
blob_buf_free(&ctx->tmp_bb);
BBFDM_INFO("END: ubus method|%s|, name|bbfdm|", ctx->ubus_method);
BBFDM_INFO("END: ubus method|%s|, name|bbfdm|, path|%s|", ctx->ubus_method, ctx->requested_path);
BBFDM_FREE(ctx);
}
@ -316,7 +314,7 @@ static void append_response_data(struct ubus_request_tracker *tracker, struct bl
static void handle_request_timeout(struct uloop_timeout *timeout)
{
struct ubus_request_tracker *tracker = container_of(timeout, struct ubus_request_tracker, timeout);
BBFDM_ERR("Timeout occurred for request: '%s'", tracker->request_name);
BBFDM_ERR("Timeout occurred for request: '%s %s'", tracker->request_name, tracker->ctx->requested_path);
ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request);
tracker->ctx->pending_requests--;
@ -344,7 +342,7 @@ static void ubus_result_callback(struct ubus_request *req, int type __attribute_
struct ubus_request_tracker *tracker = container_of(req, struct ubus_request_tracker, async_request);
if (msg) {
BBFDM_DEBUG("Response from object '%s'", tracker->request_name);
BBFDM_DEBUG("Response from object '%s %s'", tracker->request_name, tracker->ctx->requested_path);
append_response_data(tracker, msg);
}
}
@ -352,7 +350,7 @@ static void ubus_result_callback(struct ubus_request *req, int type __attribute_
static void ubus_request_complete(struct ubus_request *req, int ret)
{
struct ubus_request_tracker *tracker = container_of(req, struct ubus_request_tracker, async_request);
BBFDM_DEBUG("Request completed for '%s' with status: '%d'", tracker->request_name, ret);
BBFDM_DEBUG("Request completed for '%s %s' with status: '%d'", tracker->request_name, tracker->ctx->requested_path, ret);
uloop_timeout_cancel(&tracker->timeout);
tracker->ctx->pending_requests--;
@ -385,7 +383,7 @@ void run_async_call(struct async_request_context *ctx, service_entry_t *service,
return;
}
struct ubus_request_tracker *tracker = calloc(1, sizeof(struct ubus_request_tracker));
struct ubus_request_tracker *tracker = (struct ubus_request_tracker *)calloc(1, sizeof(struct ubus_request_tracker));
if (!tracker) {
BBFDM_ERR("Failed to allocate memory for request tracker");
return;

View file

@ -9,7 +9,6 @@
*
*/
#include <regex.h>
#include <sys/param.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>
@ -81,23 +80,6 @@ static void free_pv_list(struct list_head *pv_list)
}
}
static bool match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[])
{
regex_t re;
if (!string || !pattern)
return 0;
if (regcomp(&re, pattern, REG_EXTENDED) != 0)
return 0;
int status = regexec(&re, string, nmatch, pmatch, 0);
regfree(&re);
return (status != 0) ? false : true;
}
static bool is_node_instance(const char *path)
{
if (!path)
@ -473,7 +455,7 @@ static void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list)
static bool is_res_required(const char *str, size_t s_len, size_t *start, size_t *len)
{
if (match(str, GLOB_CHAR, 0, NULL)) {
if (str_match(str, GLOB_CHAR, 0, NULL)) {
char *star = strchr(str, '*');
*start = (star) ? (size_t)labs(star - str) : s_len;

View file

@ -22,9 +22,7 @@
LIST_HEAD(registered_services);
extern int g_log_level;
static void add_service_to_list(const char *name, int service_proto, service_object_t *objects, size_t count, bool is_unified)
static void add_service_to_list(const char *name, struct blob_buf *dm_schema, int service_proto, service_object_t *objects, size_t count, bool is_unified)
{
service_entry_t *service = NULL;
@ -33,16 +31,83 @@ static void add_service_to_list(const char *name, int service_proto, service_obj
return;
}
service = calloc(1, sizeof(service_entry_t));
service = (service_entry_t *)calloc(1, sizeof(service_entry_t));
if (!service) {
BBFDM_ERR("Failed to allocate memory");
return;
}
list_add_tail(&service->list, &registered_services);
service->name = strdup(name);
service->dm_schema = dm_schema;
service->protocol = service_proto;
service->objects = objects;
service->object_count = count;
service->is_unified = is_unified;
}
static void receive_schema_result(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *attr = NULL;
int remaining = 0;
if (msg == NULL || req == NULL)
return;
struct blob_buf *srv_schema = (struct blob_buf *)req->priv;
if (!srv_schema)
return;
struct blob_attr *results = get_results_array(msg);
if (!results)
return;
blobmsg_for_each_attr(attr, results, remaining) {
blobmsg_add_blob(srv_schema, attr);
}
}
void fill_service_schema(struct ubus_context *ubus_ctx, int ubus_timeout, const char *service_name, struct blob_buf **service_schema)
{
uint32_t ubus_id;
if (!ubus_ctx || !service_name || !service_schema)
return;
if (*service_schema != NULL) {
blob_buf_free(*service_schema);
BBFDM_FREE(*service_schema);
}
if (!ubus_lookup_id(ubus_ctx, service_name, &ubus_id)) {
struct blob_buf bb = {0};
*service_schema = (struct blob_buf *)calloc(1, sizeof(struct blob_buf));
if (*service_schema == NULL) {
BBFDM_ERR("Failed to allocate memory");
return;
}
blob_buf_init(*service_schema, 0);
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "path", BBFDM_ROOT_OBJECT);
int err = ubus_invoke(ubus_ctx, ubus_id, "schema", bb.head, receive_schema_result, (void *)*service_schema, ubus_timeout);
if (err != 0) {
BBFDM_ERR("UBUS invoke failed [object: %s, method: schema] with error (%d)", service_name, err);
}
blob_buf_free(&bb);
} else {
BBFDM_WARNING("Failed to lookup UBUS object: %s", service_name);
}
}
static int load_service_from_file(struct ubus_context *ubus_ctx, const char *filename, const char *file_path)
{
size_t num_objs = 0;
@ -75,13 +140,11 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil
return -1;
}
struct blob_buf *service_schema = NULL;
char service_name[MAX_PATH_LENGTH] = {0};
snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(filename) - 5), filename);
uint32_t ubus_id;
if (ubus_lookup_id(ubus_ctx, service_name, &ubus_id)) {
BBFDM_WARNING("Failed to lookup UBUS object: %s", service_name);
}
snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(filename) - 5), filename);
fill_service_schema(ubus_ctx, 2000, service_name, &service_schema);
json_object *unified_daemon_jobj = NULL;
json_object_object_get_ex(daemon_config, "unified_daemon", &unified_daemon_jobj);
@ -104,7 +167,12 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil
return -1;
}
service_object_t *objects = calloc(service_count, sizeof(service_object_t));
service_object_t *objects = (service_object_t *)calloc(service_count, sizeof(service_object_t));
if (!objects) {
BBFDM_ERR("Failed to allocate memory");
json_object_put(json_root);
return -1;
}
for (size_t i = 0; i < service_count; i++) {
json_object *service_obj = json_object_array_get_idx(services_array, i);
@ -127,7 +195,7 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil
}
BBFDM_INFO("Registering [%s :: %lu :: %d]", service_name, num_objs, is_unified);
add_service_to_list(service_name, service_proto, objects, num_objs, is_unified);
add_service_to_list(service_name, service_schema, service_proto, objects, num_objs, is_unified);
json_object_put(json_root);
return 0;
}
@ -184,6 +252,12 @@ void unregister_services(void)
list_for_each_entry_safe(service, tmp, &registered_services, list) {
list_del(&service->list);
if (service->dm_schema) {
blob_buf_free(service->dm_schema);
BBFDM_FREE(service->dm_schema);
}
BBFDM_FREE(service->name);
BBFDM_FREE(service->objects);
BBFDM_FREE(service);
@ -236,9 +310,9 @@ void list_registered_services(struct blob_buf *bb)
blobmsg_close_array(bb, array);
}
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service)
bool service_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service)
{
if (!proto_matches(requested_proto, service->protocol))
if (!proto_match(requested_proto, service->protocol))
return false;
if (strlen(requested_path) == 0 || strcmp(requested_path, BBFDM_ROOT_OBJECT) == 0)
@ -250,7 +324,7 @@ bool is_path_match(const char *requested_path, unsigned int requested_proto, ser
for (size_t idx = 0; idx < service->object_count; idx++) {
char current_obj[MAX_PATH_LENGTH] = {0};
if (!proto_matches(requested_proto, service->objects[idx].protocol))
if (!proto_match(requested_proto, service->objects[idx].protocol))
continue;
snprintf(current_obj, sizeof(current_obj), "%s%s", service->objects[idx].parent_path, service->objects[idx].object_name);

View file

@ -20,6 +20,7 @@ typedef struct {
typedef struct service_entry {
struct list_head list;
struct blob_buf *dm_schema;
char *name;
enum bbfdmd_type_enum protocol;
bool is_unified;
@ -32,7 +33,8 @@ typedef struct service_entry {
int register_services(struct ubus_context *ctx);
void unregister_services(void);
void list_registered_services(struct blob_buf *bb);
void fill_service_schema(struct ubus_context *ubus_ctx, int ubus_timeout, const char *service_name, struct blob_buf **service_schema);
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service);
bool service_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service);
#endif /* BBFDMD_SERVICE_H */