mirror of
https://dev.iopsys.eu/bbf/bbfdm.git
synced 2025-12-10 07:44:39 +01:00
Optimize bbfdmd
* All core Data Model move to core micro-service * New bbfdmd daemon to use async call to optimize RPCs handling
This commit is contained in:
parent
af2c564ab8
commit
f21814dd4e
72 changed files with 2246 additions and 4207 deletions
|
|
@ -15,8 +15,8 @@ include:
|
||||||
- if: $CI_COMMIT_BRANCH == "devel"
|
- if: $CI_COMMIT_BRANCH == "devel"
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- unit_test
|
|
||||||
- static_code_analysis
|
- static_code_analysis
|
||||||
|
- unit_test
|
||||||
- functional_test
|
- functional_test
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
|
|
@ -29,6 +29,7 @@ run_unit_test:
|
||||||
- "./gitlab-ci/install-dependencies.sh ms"
|
- "./gitlab-ci/install-dependencies.sh ms"
|
||||||
- "./gitlab-ci/setup.sh ms"
|
- "./gitlab-ci/setup.sh ms"
|
||||||
- "./gitlab-ci/unit-test.sh"
|
- "./gitlab-ci/unit-test.sh"
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ PROJECT(bbfdmd)
|
||||||
|
|
||||||
ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -g3 -fPIC -D_GNU_SOURCE)
|
ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -g3 -fPIC -D_GNU_SOURCE)
|
||||||
|
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/legacy -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2 -I${CMAKE_SOURCE_DIR}/libbbfdm-ubus")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}")
|
||||||
|
|
||||||
FILE(GLOB BBF_SOURCES *.c)
|
FILE(GLOB BBF_SOURCES *.c)
|
||||||
ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES})
|
ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES})
|
||||||
TARGET_LINK_LIBRARIES(bbfdmd bbfdm-ubus bbfdm)
|
TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json json-c bbfdm-api-v2)
|
||||||
INSTALL(TARGETS bbfdmd DESTINATION usr/sbin)
|
INSTALL(TARGETS bbfdmd DESTINATION usr/sbin)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,179 @@
|
||||||
/*
|
/*
|
||||||
* bbfdmd.c: BBFDMD deamon
|
* Copyright (C) 2023-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved.
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
*
|
*
|
||||||
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
|
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
|
||||||
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
*
|
*
|
||||||
* See LICENSE file for license related information.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/prctl.h>
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include <libubus.h>
|
||||||
|
#include <libubox/blobmsg_json.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bbfdm-ubus.h"
|
#include "service.h"
|
||||||
|
#include "get.h"
|
||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
|
|
||||||
#include "../../libbbfdm/device.h"
|
extern struct list_head registered_services;
|
||||||
|
extern int g_log_level;
|
||||||
|
|
||||||
|
static const struct blobmsg_policy bbfdm_policy[] = {
|
||||||
|
[BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
|
||||||
|
[BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
|
||||||
|
[BBFDM_INPUT] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *tb[__BBFDM_MAX];
|
||||||
|
service_entry_t *service = NULL;
|
||||||
|
|
||||||
|
if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) {
|
||||||
|
BBFDM_ERR("Failed to parse input message");
|
||||||
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tb[BBFDM_PATH]) {
|
||||||
|
BBFDM_ERR("%s: path must be defined", method);
|
||||||
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct async_request_context *context = calloc(1, sizeof(struct async_request_context));
|
||||||
|
if (!context) {
|
||||||
|
BBFDM_ERR("Failed to allocate memory");
|
||||||
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
|
||||||
|
|
||||||
|
snprintf(context->requested_path, sizeof(context->requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH]));
|
||||||
|
snprintf(context->ubus_method, sizeof(context->ubus_method), "%s", method);
|
||||||
|
|
||||||
|
context->ubus_ctx = ctx;
|
||||||
|
|
||||||
|
memset(&context->tmp_bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&context->tmp_bb, 0);
|
||||||
|
|
||||||
|
if (strcmp(method, "get") == 0) {
|
||||||
|
INIT_LIST_HEAD(&context->linker_list);
|
||||||
|
|
||||||
|
// Send linker cleanup event for all services
|
||||||
|
send_linker_cleanup_event(ctx);
|
||||||
|
|
||||||
|
// Event handler to wait for linker response
|
||||||
|
context->linker_handler.cb = linker_response_callback;
|
||||||
|
ubus_register_event_handler(ctx, &context->linker_handler, "bbfdm.linker.response");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int requested_proto = get_proto_type_option_value(tb[BBFDM_INPUT]);
|
||||||
|
|
||||||
|
ubus_defer_request(ctx, req, &context->request_data);
|
||||||
|
|
||||||
|
list_for_each_entry(service, ®istered_services, list) {
|
||||||
|
|
||||||
|
if (!is_path_match(context->requested_path, requested_proto, service))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
run_async_call(context, service->name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
context->service_list_processed = true;
|
||||||
|
|
||||||
|
if (context->path_matched == false)
|
||||||
|
send_response(context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *tb[__BBFDM_MAX];
|
||||||
|
service_entry_t *service = NULL;
|
||||||
|
char requested_path[MAX_PATH_LENGTH];
|
||||||
|
struct blob_buf bb = {0};
|
||||||
|
|
||||||
|
if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) {
|
||||||
|
BBFDM_ERR("Failed to parse input message");
|
||||||
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tb[BBFDM_PATH]) {
|
||||||
|
BBFDM_ERR("%s: path must be defined", method);
|
||||||
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
|
||||||
|
|
||||||
|
snprintf(requested_path, sizeof(requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH]));
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
|
||||||
|
unsigned int requested_proto = get_proto_type_option_value(tb[BBFDM_INPUT]);
|
||||||
|
|
||||||
|
list_for_each_entry(service, ®istered_services, list) {
|
||||||
|
|
||||||
|
if (!is_path_match(requested_path, requested_proto, service))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
run_sync_call(service->name, method, msg, &bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
ubus_send_reply(ctx, req, bb.head);
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bbfdm_services_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method, struct blob_attr *msg __attribute__((unused)))
|
||||||
|
{
|
||||||
|
struct blob_buf bb;
|
||||||
|
|
||||||
|
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
|
||||||
|
list_registered_services(&bb);
|
||||||
|
|
||||||
|
ubus_send_reply(ctx, req, bb.head);
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ubus_method bbfdm_methods[] = {
|
||||||
|
UBUS_METHOD("get", bbfdm_handler_async, bbfdm_policy),
|
||||||
|
UBUS_METHOD("schema", bbfdm_handler_async, bbfdm_policy),
|
||||||
|
UBUS_METHOD("instances", bbfdm_handler_async, bbfdm_policy),
|
||||||
|
UBUS_METHOD("operate", bbfdm_handler_async, bbfdm_policy),
|
||||||
|
UBUS_METHOD("set", bbfdm_handler_sync, bbfdm_policy),
|
||||||
|
UBUS_METHOD("add", bbfdm_handler_sync, bbfdm_policy),
|
||||||
|
UBUS_METHOD("del", bbfdm_handler_sync, bbfdm_policy),
|
||||||
|
UBUS_METHOD_NOARG("services", bbfdm_services_handler)
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ubus_object_type bbfdm_object_type = UBUS_OBJECT_TYPE(BBFDM_UBUS_OBJECT, bbfdm_methods);
|
||||||
|
|
||||||
|
static struct ubus_object bbfdm_object = {
|
||||||
|
.name = BBFDM_UBUS_OBJECT,
|
||||||
|
.type = &bbfdm_object_type,
|
||||||
|
.methods = bbfdm_methods,
|
||||||
|
.n_methods = ARRAY_SIZE(bbfdm_methods)
|
||||||
|
};
|
||||||
|
|
||||||
static void usage(char *prog)
|
static void usage(char *prog)
|
||||||
{
|
{
|
||||||
|
|
@ -30,13 +188,10 @@ static void usage(char *prog)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bbfdm_context bbfdm_ctx = {0};
|
struct ubus_context ubus_ctx = {0};
|
||||||
char *cli_argv[4] = {0};
|
char *cli_argv[4] = {0};
|
||||||
int log_level = 3; // Default is LOG_ERR
|
|
||||||
int err = 0, ch, cli_argc = 0, i;
|
int err = 0, ch, cli_argc = 0, i;
|
||||||
|
|
||||||
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
|
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "hc:l:")) != -1) {
|
while ((ch = getopt(argc, argv, "hc:l:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
|
|
@ -47,9 +202,9 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
if (optarg) {
|
if (optarg) {
|
||||||
log_level = (int)strtod(optarg, NULL);
|
g_log_level = (int)strtod(optarg, NULL);
|
||||||
if (log_level < 0 || log_level > 7)
|
if (g_log_level < 0 || g_log_level > 7)
|
||||||
log_level = 3;
|
g_log_level = 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
@ -61,24 +216,42 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli_argc) {
|
if (cli_argc) {
|
||||||
return bbfdm_cli_exec_command(cli_argc, cli_argv);
|
return bbfdmd_cli_exec_command(cli_argc, cli_argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bbfdm_ubus_set_log_level(log_level);
|
openlog(BBFDM_UBUS_OBJECT, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
|
||||||
bbfdm_ubus_load_data_model(tDynamicObj);
|
|
||||||
|
|
||||||
openlog(BBFDM_DEFAULT_UBUS_OBJ, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
|
setlogmask(LOG_UPTO(g_log_level));
|
||||||
|
|
||||||
err = bbfdm_ubus_regiter_init(&bbfdm_ctx);
|
err = ubus_connect_ctx(&ubus_ctx, NULL);
|
||||||
if (err != 0)
|
if (err != UBUS_STATUS_OK) {
|
||||||
goto exit;
|
BBFDM_ERR("Failed to connect to ubus");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
BBF_INFO("Waiting on uloop....");
|
uloop_init();
|
||||||
|
ubus_add_uloop(&ubus_ctx);
|
||||||
|
|
||||||
|
err = register_services(&ubus_ctx);
|
||||||
|
if (err) {
|
||||||
|
BBFDM_ERR("Failed to load micro-services");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ubus_add_object(&ubus_ctx, &bbfdm_object);
|
||||||
|
if (err != UBUS_STATUS_OK) {
|
||||||
|
BBFDM_ERR("Failed to add ubus object: %s", ubus_strerror(err));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_INFO("Waiting on uloop....");
|
||||||
uloop_run();
|
uloop_run();
|
||||||
|
|
||||||
exit:
|
end:
|
||||||
if (err != -5) // Error code is not -5, indicating that ubus_ctx is connected, proceed with shutdown
|
BBFDM_ERR("Free context");
|
||||||
bbfdm_ubus_regiter_free(&bbfdm_ctx);
|
unregister_services();
|
||||||
|
uloop_done();
|
||||||
|
ubus_shutdown(&ubus_ctx);
|
||||||
|
|
||||||
closelog();
|
closelog();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
/*
|
/*
|
||||||
* cli.c: Cli command for bbfdmd
|
* Copyright (C) 2023-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
*
|
*
|
||||||
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
*
|
*
|
||||||
* See LICENSE file for license related information.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libubus.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
#define UNUSED __attribute__((unused))
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
@ -28,7 +30,7 @@ typedef struct {
|
||||||
char *usage;
|
char *usage;
|
||||||
} cli_cmd_t;
|
} cli_cmd_t;
|
||||||
|
|
||||||
static int cli_exec_help(cli_data_t *cli_data UNUSED, const char *path UNUSED, const char *value UNUSED);
|
static int cli_exec_help(cli_data_t *cli_data __attribute__((unused)), const char *path __attribute__((unused)), const char *value __attribute__((unused)));
|
||||||
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value);
|
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value);
|
||||||
|
|
||||||
cli_cmd_t cli_commands[] = {
|
cli_cmd_t cli_commands[] = {
|
||||||
|
|
@ -138,10 +140,8 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__(
|
||||||
} else if (strcmp(cli_data->cmd, "instances") == 0) {
|
} else if (strcmp(cli_data->cmd, "instances") == 0) {
|
||||||
printf("%s\n", name);
|
printf("%s\n", name);
|
||||||
} else if (strcmp(cli_data->cmd, "schema") == 0) {
|
} else if (strcmp(cli_data->cmd, "schema") == 0) {
|
||||||
char *type = tb[2] ? blobmsg_get_string(tb[2]) : "";
|
char *type = tb[2] ? blobmsg_get_string(tb[2]) : "xsd:string";
|
||||||
int cmd = get_dm_type(type);
|
printf("%s %s\n", name, type);
|
||||||
|
|
||||||
printf("%s %s %s\n", name, type, (cmd != DMT_EVENT && cmd != DMT_COMMAND) ? data : "0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_data->ubus_status = true;
|
cli_data->ubus_status = true;
|
||||||
|
|
@ -151,7 +151,6 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__(
|
||||||
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value)
|
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value)
|
||||||
{
|
{
|
||||||
struct blob_buf b = {0};
|
struct blob_buf b = {0};
|
||||||
void *table = NULL;
|
|
||||||
int err = EXIT_SUCCESS;
|
int err = EXIT_SUCCESS;
|
||||||
|
|
||||||
memset(&b, 0, sizeof(struct blob_buf));
|
memset(&b, 0, sizeof(struct blob_buf));
|
||||||
|
|
@ -159,21 +158,17 @@ static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *valu
|
||||||
blob_buf_init(&b, 0);
|
blob_buf_init(&b, 0);
|
||||||
|
|
||||||
blobmsg_add_string(&b, "path", path);
|
blobmsg_add_string(&b, "path", path);
|
||||||
if (value) blobmsg_add_string(&b, "value", value);
|
blobmsg_add_string(&b, "value", value ? value : "");
|
||||||
|
|
||||||
table = blobmsg_open_table(&b, "optional");
|
int e = bbfdm_ubus_invoke(BBFDM_UBUS_OBJECT, cli_data->cmd, b.head, __ubus_callback, cli_data);
|
||||||
blobmsg_add_string(&b, "format", "raw");
|
|
||||||
blobmsg_close_table(&b, table);
|
|
||||||
|
|
||||||
int e = bbfdm_ubus_invoke(BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd, b.head, __ubus_callback, cli_data);
|
|
||||||
|
|
||||||
if (e < 0) {
|
if (e < 0) {
|
||||||
printf("ERROR: ubus invoke for [object:%s method:%s] exit with error(%d)\n", BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd, e);
|
printf("ERROR: ubus invoke for [object:%s method:%s] exit with error(%d)\n", BBFDM_UBUS_OBJECT, cli_data->cmd, e);
|
||||||
err = EXIT_FAILURE;
|
err = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli_data->ubus_status == false) {
|
if (cli_data->ubus_status == false) {
|
||||||
printf("ERROR: ubus call for [object:%s method:%s] exit with error\n", BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd);
|
printf("ERROR: ubus call for [object:%s method:%s] exit with error\n", BBFDM_UBUS_OBJECT, cli_data->cmd);
|
||||||
err = EXIT_FAILURE;
|
err = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +177,7 @@ static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *valu
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cli_exec_help(cli_data_t *cli_data UNUSED, const char *path UNUSED, const char *value UNUSED)
|
static int cli_exec_help(cli_data_t *cli_data __attribute__((unused)), const char *path __attribute__((unused)), const char *value __attribute__((unused)))
|
||||||
{
|
{
|
||||||
cli_cmd_t *cli_cmd;
|
cli_cmd_t *cli_cmd;
|
||||||
|
|
||||||
|
|
@ -236,7 +231,7 @@ end:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bbfdm_cli_exec_command(int argc, char *argv[])
|
int bbfdmd_cli_exec_command(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
cli_data_t cli_data = {0};
|
cli_data_t cli_data = {0};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
/*
|
/*
|
||||||
* cli.c: Cli command for bbfdmd
|
* Copyright (C) 2023-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
*
|
*
|
||||||
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
*
|
*
|
||||||
* See LICENSE file for license related information.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int bbfdm_cli_exec_command(int argc, char *argv[]);
|
#ifndef BBFDMD_CLI_H
|
||||||
|
#define BBFDMD_CLI_H
|
||||||
|
|
||||||
|
int bbfdmd_cli_exec_command(int argc, char *argv[]);
|
||||||
|
|
||||||
|
#endif /* BBFDMD_CLI_H */
|
||||||
|
|
|
||||||
140
bbfdmd/ubus/common.c
Normal file
140
bbfdmd/ubus/common.c
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <libubox/blobmsg_json.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int g_log_level = LOG_ERR;
|
||||||
|
|
||||||
|
unsigned int get_proto_type(const char *proto)
|
||||||
|
{
|
||||||
|
int type = BBFDMD_BOTH;
|
||||||
|
|
||||||
|
if (proto) {
|
||||||
|
if (strcmp(proto, "cwmp") == 0)
|
||||||
|
type = BBFDMD_CWMP;
|
||||||
|
else if (strcmp(proto, "usp") == 0)
|
||||||
|
type = BBFDMD_USP;
|
||||||
|
else
|
||||||
|
type = BBFDMD_BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int get_proto_type_option_value(struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *tb[1] = {0};
|
||||||
|
const struct blobmsg_policy p[1] = {
|
||||||
|
{ "proto", BLOBMSG_TYPE_STRING }
|
||||||
|
};
|
||||||
|
int proto = BBFDMD_BOTH;
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return proto;
|
||||||
|
|
||||||
|
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
|
||||||
|
|
||||||
|
if (tb[0]) {
|
||||||
|
const char *val = blobmsg_get_string(tb[0]);
|
||||||
|
proto = get_proto_type(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type)
|
||||||
|
{
|
||||||
|
return (dm_type == BBFDMD_BOTH || type == BBFDMD_BOTH || dm_type == type) && type != BBFDMD_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sync_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
int remaining = 0;
|
||||||
|
|
||||||
|
if (!req || !msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct blob_buf *bb_response = (struct blob_buf *)req->priv;
|
||||||
|
|
||||||
|
if (!bb_response)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blob_for_each_attr(attr, msg, remaining) {
|
||||||
|
blobmsg_add_field(bb_response, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response)
|
||||||
|
{
|
||||||
|
struct blob_buf req_buf = {0};
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
int remaining = 0;
|
||||||
|
|
||||||
|
if (!ubus_obj || !ubus_method || !msg || !bb_response)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&req_buf, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&req_buf, 0);
|
||||||
|
|
||||||
|
blob_for_each_attr(attr, msg, remaining) {
|
||||||
|
if (strcmp(ubus_method, "set") == 0 &&
|
||||||
|
strcmp(blobmsg_name(attr), "value") == 0 &&
|
||||||
|
blobmsg_type(attr) == BLOBMSG_TYPE_STRING &&
|
||||||
|
strncmp(BBFDM_ROOT_OBJECT, blobmsg_get_string(attr), strlen(BBFDM_ROOT_OBJECT)) == 0) {
|
||||||
|
char value_in[MAX_PATH_LENGTH];
|
||||||
|
|
||||||
|
char *reference_value = get_reference_data(blobmsg_get_string(attr), "reference_value");
|
||||||
|
snprintf(value_in, sizeof(value_in), "%s=>%s##", blobmsg_get_string(attr), reference_value ? reference_value : "");
|
||||||
|
BBFDM_FREE(reference_value);
|
||||||
|
|
||||||
|
blobmsg_add_string(&req_buf, blobmsg_name(attr), value_in);
|
||||||
|
} if (strcmp(ubus_method, "set") == 0 &&
|
||||||
|
strcmp(blobmsg_name(attr), "obj_path") == 0 &&
|
||||||
|
blobmsg_type(attr) == BLOBMSG_TYPE_TABLE) {
|
||||||
|
struct blob_attr *__attr = NULL;
|
||||||
|
int rem = 0;
|
||||||
|
|
||||||
|
void *table = blobmsg_open_table(&req_buf, "obj_path");
|
||||||
|
|
||||||
|
blobmsg_for_each_attr(__attr, attr, rem) {
|
||||||
|
if (blobmsg_type(__attr) == BLOBMSG_TYPE_STRING && strncmp(BBFDM_ROOT_OBJECT, blobmsg_get_string(__attr), strlen(BBFDM_ROOT_OBJECT)) == 0) {
|
||||||
|
char value_in[MAX_PATH_LENGTH];
|
||||||
|
|
||||||
|
char *reference_value = get_reference_data(blobmsg_get_string(__attr), "reference_value");
|
||||||
|
snprintf(value_in, sizeof(value_in), "%s=>%s##", blobmsg_get_string(__attr), reference_value ? reference_value : "");
|
||||||
|
BBFDM_FREE(reference_value);
|
||||||
|
|
||||||
|
blobmsg_add_string(&req_buf, blobmsg_name(__attr), value_in);
|
||||||
|
} else {
|
||||||
|
blobmsg_add_string(&req_buf, blobmsg_name(__attr), blobmsg_get_string(__attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_close_table(&req_buf, table);
|
||||||
|
} else {
|
||||||
|
blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_log_level == LOG_DEBUG) {
|
||||||
|
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
|
||||||
|
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ubus_method, json_str);
|
||||||
|
BBFDM_FREE(json_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_UBUS_INVOKE_SYNC(ubus_obj, ubus_method, req_buf.head, 2000, sync_callback, bb_response);
|
||||||
|
|
||||||
|
blob_buf_free(&req_buf);
|
||||||
|
}
|
||||||
42
bbfdmd/ubus/common.h
Normal file
42
bbfdmd/ubus/common.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BBFDMD_COMMON_H
|
||||||
|
#define BBFDMD_COMMON_H
|
||||||
|
|
||||||
|
#include "libbbfdm-api/version-2/bbfdm_api.h"
|
||||||
|
|
||||||
|
#define BBFDM_ROOT_OBJECT "Device."
|
||||||
|
#define BBFDM_UBUS_OBJECT "bbfdm"
|
||||||
|
#define BBFDM_ADD_EVENT "AddObj"
|
||||||
|
#define BBFDM_DEL_EVENT "DelObj"
|
||||||
|
#define BBFDM_EVENT_NAME "event"
|
||||||
|
#define BBFDM_MICROSERVICE_INPUT_PATH "/etc/bbfdm/services"
|
||||||
|
#define MAX_PATH_LENGTH 1024
|
||||||
|
#define SERVICE_CALL_TIMEOUT 5000 // 5 secs
|
||||||
|
#define SERVICE_CALL_OPERATE_TIMEOUT 1800000 // 30 mins
|
||||||
|
|
||||||
|
enum bbfdmd_type_enum {
|
||||||
|
BBFDMD_NONE = 0,
|
||||||
|
BBFDMD_CWMP = 1<<0,
|
||||||
|
BBFDMD_USP = 1<<1,
|
||||||
|
BBFDMD_BOTH = BBFDMD_CWMP | BBFDMD_USP,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int get_proto_type(const char *proto);
|
||||||
|
unsigned int get_proto_type_option_value(struct blob_attr *msg);
|
||||||
|
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type);
|
||||||
|
|
||||||
|
char *get_reference_data(const char *path, const char *method_name);
|
||||||
|
|
||||||
|
void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response);
|
||||||
|
|
||||||
|
#endif /* BBFDMD_COMMON_H */
|
||||||
350
bbfdmd/ubus/get.c
Normal file
350
bbfdmd/ubus/get.c
Normal file
|
|
@ -0,0 +1,350 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libubus.h>
|
||||||
|
#include <libubox/blobmsg_json.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "get.h"
|
||||||
|
|
||||||
|
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)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_add_tail(&linker->list, &ctx->linker_list);
|
||||||
|
linker->path = strdup(linker_path ? linker_path : "");
|
||||||
|
linker->value = strdup(linker_value ? linker_value : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_linker_entries(struct async_request_context *ctx)
|
||||||
|
{
|
||||||
|
struct linker_args *linker = NULL, *tmp = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(linker, tmp, &ctx->linker_list, list) {
|
||||||
|
list_del(&linker->list);
|
||||||
|
BBFDM_FREE(linker->path);
|
||||||
|
BBFDM_FREE(linker->value);
|
||||||
|
BBFDM_FREE(linker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_blob_param(struct blob_buf *bb, const char *path, const char *data, const char *type)
|
||||||
|
{
|
||||||
|
if (!bb || !path || !data || !type)
|
||||||
|
return;
|
||||||
|
|
||||||
|
void *table = blobmsg_open_table(bb, NULL);
|
||||||
|
|
||||||
|
blobmsg_add_string(bb, "path", path);
|
||||||
|
blobmsg_add_string(bb, "data", data);
|
||||||
|
blobmsg_add_string(bb, "type", type);
|
||||||
|
|
||||||
|
blobmsg_close_table(bb, table);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolve_reference_path(struct async_request_context *ctx, char *ref_path, char *output, size_t output_len)
|
||||||
|
{
|
||||||
|
char *token = NULL, *saveptr = NULL;
|
||||||
|
char buffer[MAX_PATH_LENGTH] = {0};
|
||||||
|
|
||||||
|
if (!ref_path || !output || !output_len) {
|
||||||
|
BBFDM_ERR("Invalid arguments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize output buffer
|
||||||
|
output[0] = 0;
|
||||||
|
|
||||||
|
// Return if reference path is empty
|
||||||
|
if (strlen(ref_path) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s", ref_path);
|
||||||
|
|
||||||
|
for (token = strtok_r(buffer, ",", &saveptr); token; token = strtok_r(NULL, ",", &saveptr)) {
|
||||||
|
|
||||||
|
// Reference is found, don't need to parse the list
|
||||||
|
if (!strchr(token, '[')) {
|
||||||
|
snprintf(output, output_len, "%s", token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct linker_args *linker = NULL;
|
||||||
|
list_for_each_entry(linker, &ctx->linker_list, list) {
|
||||||
|
// Reference is found in the resolved list
|
||||||
|
if (strcmp(linker->path, token) == 0 && strlen(linker->value) != 0) {
|
||||||
|
snprintf(output, output_len, "%s", linker->value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference is not found in the resolved list
|
||||||
|
{
|
||||||
|
// Try to get reference value from micro-services directly
|
||||||
|
char *reference_path = get_reference_data(token, "reference_path");
|
||||||
|
|
||||||
|
// Add path to list in order to be used by other parameters
|
||||||
|
add_linker_entry(ctx, token, reference_path ? reference_path : "");
|
||||||
|
|
||||||
|
// Reference value is found
|
||||||
|
if (reference_path != NULL) {
|
||||||
|
snprintf(output, output_len, "%s", reference_path);
|
||||||
|
BBFDM_FREE(reference_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_ERR("Can't resolve reference path '%s' -> Set its value to empty", ref_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_and_send_response(struct async_request_context *ctx)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
struct blob_buf bb = {0};
|
||||||
|
int remaining = 0;
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
|
||||||
|
void *array = blobmsg_open_array(&bb, "results");
|
||||||
|
|
||||||
|
if (ctx->path_matched == false) {
|
||||||
|
void *table = blobmsg_open_table(&bb, NULL);
|
||||||
|
blobmsg_add_string(&bb, "path", ctx->requested_path);
|
||||||
|
blobmsg_add_u32(&bb, "fault", 9005);
|
||||||
|
blobmsg_add_string(&bb, "fault_msg", "Invalid parameter name");
|
||||||
|
blobmsg_close_table(&bb, table);
|
||||||
|
} else {
|
||||||
|
blobmsg_for_each_attr(attr, ctx->tmp_bb.head, remaining) {
|
||||||
|
|
||||||
|
if (strcmp(ctx->ubus_method, "get") == 0) {
|
||||||
|
struct blob_attr *fields[4];
|
||||||
|
const struct blobmsg_policy policy[4] = {
|
||||||
|
{ "path", BLOBMSG_TYPE_STRING },
|
||||||
|
{ "data", BLOBMSG_TYPE_STRING },
|
||||||
|
{ "type", BLOBMSG_TYPE_STRING },
|
||||||
|
{ "reference", BLOBMSG_TYPE_BOOL },
|
||||||
|
};
|
||||||
|
|
||||||
|
blobmsg_parse(policy, 4, fields, blobmsg_data(attr), blobmsg_len(attr));
|
||||||
|
|
||||||
|
bool is_reference = fields[3] ? blobmsg_get_u8(fields[3]) : false;
|
||||||
|
|
||||||
|
if (is_reference) {
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
|
||||||
|
char *path = fields[0] ? blobmsg_get_string(fields[0]) : "";
|
||||||
|
char *data = fields[1] ? blobmsg_get_string(fields[1]) : "";
|
||||||
|
char *type = fields[2] ? blobmsg_get_string(fields[2]) : "";
|
||||||
|
|
||||||
|
resolve_reference_path(ctx, data, buffer, sizeof(buffer));
|
||||||
|
fill_blob_param(&bb, path, buffer, type);
|
||||||
|
} else {
|
||||||
|
blobmsg_add_blob(&bb, attr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blobmsg_add_blob(&bb, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_close_array(&bb, array);
|
||||||
|
|
||||||
|
ubus_send_reply(ctx->ubus_ctx, &ctx->request_data, bb.head);
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_response(struct async_request_context *ctx)
|
||||||
|
{
|
||||||
|
prepare_and_send_response(ctx);
|
||||||
|
|
||||||
|
if (strcmp(ctx->ubus_method, "get") == 0) {
|
||||||
|
ubus_unregister_event_handler(ctx->ubus_ctx, &ctx->linker_handler);
|
||||||
|
send_linker_cleanup_event(ctx->ubus_ctx);
|
||||||
|
free_linker_entries(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ubus_complete_deferred_request(ctx->ubus_ctx, &ctx->request_data, UBUS_STATUS_OK);
|
||||||
|
blob_buf_free(&ctx->tmp_bb);
|
||||||
|
BBFDM_FREE(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct blob_attr *get_results_array(struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *tb[1] = {0};
|
||||||
|
const struct blobmsg_policy p[1] = {
|
||||||
|
{ "results", BLOBMSG_TYPE_ARRAY }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (msg == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
|
||||||
|
|
||||||
|
return tb[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_response_data(struct ubus_request_tracker *tracker, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
int remaining = 0;
|
||||||
|
|
||||||
|
if (!tracker || !msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct blob_attr *results = get_results_array(msg);
|
||||||
|
if (!results)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blobmsg_for_each_attr(attr, results, remaining) {
|
||||||
|
blobmsg_add_blob(&tracker->ctx->tmp_bb, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request);
|
||||||
|
tracker->ctx->pending_requests--;
|
||||||
|
|
||||||
|
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
|
||||||
|
BBFDM_ERR("All requests completed after timeout");
|
||||||
|
send_response(tracker->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_FREE(tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ubus_result_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg __attribute__((unused)))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
append_response_data(tracker, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
uloop_timeout_cancel(&tracker->timeout);
|
||||||
|
tracker->ctx->pending_requests--;
|
||||||
|
|
||||||
|
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
|
||||||
|
BBFDM_DEBUG("Result Callback: All requests completed");
|
||||||
|
send_response(tracker->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_FREE(tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_buf req_buf = {0};
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
int remaining = 0;
|
||||||
|
uint32_t id = 0;
|
||||||
|
|
||||||
|
if (!ctx || !ubus_obj || !msg) {
|
||||||
|
BBFDM_ERR("Invalid arguments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ubus_lookup_id(ctx->ubus_ctx, ubus_obj, &id)) {
|
||||||
|
BBFDM_ERR("Failed to lookup object: %s", ubus_obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ubus_request_tracker *tracker = calloc(1, sizeof(struct ubus_request_tracker));
|
||||||
|
if (!tracker) {
|
||||||
|
BBFDM_ERR("Failed to allocate memory for request tracker");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker->ctx = ctx;
|
||||||
|
ctx->pending_requests++;
|
||||||
|
ctx->path_matched = true;
|
||||||
|
|
||||||
|
memset(&req_buf, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&req_buf, 0);
|
||||||
|
|
||||||
|
blob_for_each_attr(attr, msg, remaining) {
|
||||||
|
blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", ubus_obj, ctx->ubus_method);
|
||||||
|
|
||||||
|
tracker->timeout.cb = handle_request_timeout;
|
||||||
|
uloop_timeout_set(&tracker->timeout, !strcmp(ctx->ubus_method, "operate") ? SERVICE_CALL_OPERATE_TIMEOUT : SERVICE_CALL_TIMEOUT);
|
||||||
|
|
||||||
|
if (g_log_level == LOG_DEBUG) {
|
||||||
|
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
|
||||||
|
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ctx->ubus_method, json_str);
|
||||||
|
BBFDM_FREE(json_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ubus_invoke_async(ctx->ubus_ctx, id, ctx->ubus_method, req_buf.head, &tracker->async_request)) {
|
||||||
|
BBFDM_ERR("Failed to invoke async method for object: %s", tracker->request_name);
|
||||||
|
uloop_timeout_cancel(&tracker->timeout);
|
||||||
|
BBFDM_FREE(tracker);
|
||||||
|
} else {
|
||||||
|
tracker->async_request.data_cb = ubus_result_callback;
|
||||||
|
tracker->async_request.complete_cb = ubus_request_complete;
|
||||||
|
ubus_complete_request_async(ctx->ubus_ctx, &tracker->async_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
blob_buf_free(&req_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_linker_cleanup_event(struct ubus_context *ctx)
|
||||||
|
{
|
||||||
|
struct blob_buf bb = {0};
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
ubus_send_event(ctx, "bbfdm.linker.cleanup", bb.head);
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void linker_response_callback(struct ubus_context *ctx __attribute__((unused)), struct ubus_event_handler *ev, const char *type __attribute__((unused)), struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct async_request_context *context = NULL;
|
||||||
|
struct blob_attr *attr = NULL;
|
||||||
|
size_t rem = 0;
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context = container_of(ev, struct async_request_context, linker_handler);
|
||||||
|
if (context == NULL) {
|
||||||
|
BBFDM_ERR("Failed to get the request context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_for_each_attr(attr, msg, rem) {
|
||||||
|
BBFDM_DEBUG("LINKER RESPONSE: '%s' <=> '%s'", blobmsg_name(attr), blobmsg_get_string(attr));
|
||||||
|
add_linker_entry(context, blobmsg_name(attr), blobmsg_get_string(attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
54
bbfdmd/ubus/get.h
Normal file
54
bbfdmd/ubus/get.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BBFDMD_GET_H
|
||||||
|
#define BBFDMD_GET_H
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BBFDM_PATH,
|
||||||
|
BBFDM_VALUE,
|
||||||
|
BBFDM_INPUT,
|
||||||
|
__BBFDM_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct linker_args {
|
||||||
|
struct list_head list;
|
||||||
|
char *path;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct async_request_context {
|
||||||
|
struct ubus_context *ubus_ctx;
|
||||||
|
struct ubus_request_data request_data;
|
||||||
|
struct ubus_event_handler linker_handler;
|
||||||
|
struct list_head linker_list;
|
||||||
|
struct blob_buf tmp_bb;
|
||||||
|
bool service_list_processed;
|
||||||
|
bool path_matched;
|
||||||
|
int pending_requests;
|
||||||
|
char requested_path[MAX_PATH_LENGTH];
|
||||||
|
char ubus_method[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ubus_request_tracker {
|
||||||
|
struct async_request_context *ctx;
|
||||||
|
struct ubus_request async_request;
|
||||||
|
struct uloop_timeout timeout;
|
||||||
|
char request_name[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
void send_linker_cleanup_event(struct ubus_context *ctx);
|
||||||
|
void linker_response_callback(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg);
|
||||||
|
|
||||||
|
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg);
|
||||||
|
void send_response(struct async_request_context *ctx);
|
||||||
|
|
||||||
|
#endif /* BBFDMD_GET_H */
|
||||||
319
bbfdmd/ubus/service.c
Normal file
319
bbfdmd/ubus/service.c
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include <libubox/blobmsg_json.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
service_entry_t *service = NULL;
|
||||||
|
|
||||||
|
if (!name || !objects || count == 0) {
|
||||||
|
BBFDM_ERR("Invalid service registration parameters");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
service = calloc(1, sizeof(service_entry_t));
|
||||||
|
list_add_tail(&service->list, ®istered_services);
|
||||||
|
|
||||||
|
service->name = strdup(name);
|
||||||
|
service->protocol = service_proto;
|
||||||
|
service->objects = objects;
|
||||||
|
service->object_count = count;
|
||||||
|
service->is_unified = is_unified;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_service_from_file(struct ubus_context *ubus_ctx, const char *filename, const char *file_path)
|
||||||
|
{
|
||||||
|
size_t num_objs = 0;
|
||||||
|
|
||||||
|
if (!filename || !file_path) {
|
||||||
|
BBFDM_ERR("Invalid filename or file path");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *json_root = json_object_from_file(file_path);
|
||||||
|
if (!json_root) {
|
||||||
|
BBFDM_ERR("Failed to read JSON file: %s", file_path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *daemon_config = NULL;
|
||||||
|
json_object_object_get_ex(json_root, "daemon", &daemon_config);
|
||||||
|
if (!daemon_config) {
|
||||||
|
BBFDM_ERR("Failed to find daemon object");
|
||||||
|
json_object_put(json_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *enable_jobj = NULL;
|
||||||
|
json_object_object_get_ex(daemon_config, "enable", &enable_jobj);
|
||||||
|
bool enable = enable_jobj ? json_object_get_boolean(enable_jobj) : false;
|
||||||
|
if (!enable) {
|
||||||
|
BBFDM_INFO("Service is disabled, Skipping service");
|
||||||
|
json_object_put(json_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ERR("Failed to lookup UBUS object: %s", service_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *unified_daemon_jobj = NULL;
|
||||||
|
json_object_object_get_ex(daemon_config, "unified_daemon", &unified_daemon_jobj);
|
||||||
|
bool is_unified = unified_daemon_jobj ? json_object_get_boolean(unified_daemon_jobj) : false;
|
||||||
|
|
||||||
|
json_object *proto_jobj = NULL;
|
||||||
|
json_object_object_get_ex(daemon_config, "proto", &proto_jobj);
|
||||||
|
int service_proto = get_proto_type(proto_jobj ? json_object_get_string(proto_jobj) : "");
|
||||||
|
|
||||||
|
json_object *services_array = NULL;
|
||||||
|
if (!json_object_object_get_ex(daemon_config, "services", &services_array) || json_object_get_type(services_array) != json_type_array) {
|
||||||
|
json_object_put(json_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t service_count = json_object_array_length(services_array);
|
||||||
|
if (service_count == 0) {
|
||||||
|
BBFDM_ERR("Skipping service '%s' due to no objects defined", service_name);
|
||||||
|
json_object_put(json_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service_object_t *objects = calloc(service_count, sizeof(service_object_t));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < service_count; i++) {
|
||||||
|
json_object *service_obj = json_object_array_get_idx(services_array, i);
|
||||||
|
json_object *parent_dm = NULL, *object = NULL, *proto = NULL;
|
||||||
|
|
||||||
|
json_object_object_get_ex(service_obj, "parent_dm", &parent_dm);
|
||||||
|
json_object_object_get_ex(service_obj, "object", &object);
|
||||||
|
json_object_object_get_ex(service_obj, "proto", &proto);
|
||||||
|
|
||||||
|
snprintf(objects[num_objs].parent_path, sizeof(objects[num_objs].parent_path), "%s", parent_dm ? json_object_get_string(parent_dm) : "");
|
||||||
|
snprintf(objects[num_objs].object_name, sizeof(objects[num_objs].object_name), "%s", object ? json_object_get_string(object) : "");
|
||||||
|
|
||||||
|
if (strlen(objects[num_objs].parent_path) == 0 || strlen(objects[num_objs].object_name) == 0) {
|
||||||
|
BBFDM_ERR("Skip empty registration parent_dm[%s] or object[%s]", objects[num_objs].parent_path, objects[num_objs].object_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
objects[num_objs].protocol = get_proto_type(proto ? json_object_get_string(proto) : "");
|
||||||
|
num_objs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
json_object_put(json_root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int filter(const struct dirent *entry)
|
||||||
|
{
|
||||||
|
return entry->d_name[0] != '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare(const struct dirent **a, const struct dirent **b)
|
||||||
|
{
|
||||||
|
size_t len_a = strlen((*a)->d_name);
|
||||||
|
size_t len_b = strlen((*b)->d_name);
|
||||||
|
|
||||||
|
if (len_a < len_b) // Sort by length (shorter first)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len_a > len_b)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return strcasecmp((*a)->d_name, (*b)->d_name); // If lengths are equal, sort alphabetically
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_services(struct ubus_context *ubus_ctx)
|
||||||
|
{
|
||||||
|
struct dirent **namelist;
|
||||||
|
|
||||||
|
int num_files = scandir(BBFDM_MICROSERVICE_INPUT_PATH, &namelist, filter, compare);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_files; i++) {
|
||||||
|
char file_path[512] = {0};
|
||||||
|
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s/%s", BBFDM_MICROSERVICE_INPUT_PATH, namelist[i]->d_name);
|
||||||
|
|
||||||
|
if (!bbfdm_file_exists(file_path) || !bbfdm_is_regular_file(file_path)) {
|
||||||
|
BBFDM_FREE(namelist[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (load_service_from_file(ubus_ctx, namelist[i]->d_name, file_path)) {
|
||||||
|
BBFDM_ERR("Failed to load service: %s", namelist[i]->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_FREE(namelist[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_FREE(namelist);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister_services(void)
|
||||||
|
{
|
||||||
|
service_entry_t *service = NULL, *tmp = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(service, tmp, ®istered_services, list) {
|
||||||
|
list_del(&service->list);
|
||||||
|
BBFDM_FREE(service->name);
|
||||||
|
BBFDM_FREE(service->objects);
|
||||||
|
BBFDM_FREE(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_registered_services(struct blob_buf *bb)
|
||||||
|
{
|
||||||
|
service_entry_t *service = NULL;
|
||||||
|
|
||||||
|
if (!bb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
void *array = blobmsg_open_array(bb, "registered_services");
|
||||||
|
|
||||||
|
list_for_each_entry(service, ®istered_services, list) {
|
||||||
|
void *table = blobmsg_open_table(bb, NULL);
|
||||||
|
blobmsg_add_string(bb, "name", service->name ? service->name : "");
|
||||||
|
blobmsg_add_string(bb, "proto", service->protocol == BBFDMD_USP ? "usp" : service->protocol == BBFDMD_CWMP ? "cwmp" : "both");
|
||||||
|
blobmsg_add_u8(bb, "unified_daemon", service->is_unified);
|
||||||
|
void *objects_array = blobmsg_open_array(bb, "objects");
|
||||||
|
for (size_t i = 0; i < service->object_count; i++) {
|
||||||
|
void *obj_table = blobmsg_open_table(bb, NULL);
|
||||||
|
blobmsg_add_string(bb, "parent_dm", service->objects[i].parent_path);
|
||||||
|
blobmsg_add_string(bb, "object", service->objects[i].object_name);
|
||||||
|
blobmsg_add_string(bb, "proto", service->objects[i].protocol == BBFDMD_USP ? "usp" : service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both");
|
||||||
|
blobmsg_close_table(bb, obj_table);
|
||||||
|
}
|
||||||
|
blobmsg_close_array(bb, objects_array);
|
||||||
|
blobmsg_close_table(bb, table);
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_close_array(bb, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service)
|
||||||
|
{
|
||||||
|
if (!proto_matches(requested_proto, service->protocol))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strlen(requested_path) == 0 || strcmp(requested_path, BBFDM_ROOT_OBJECT) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (strncmp(BBFDM_ROOT_OBJECT, requested_path, strlen(BBFDM_ROOT_OBJECT)) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(current_obj, sizeof(current_obj), "%s%s", service->objects[idx].parent_path, service->objects[idx].object_name);
|
||||||
|
|
||||||
|
if (strncmp(current_obj, requested_path, strlen(current_obj)) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (strncmp(requested_path, current_obj, strlen(requested_path)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_ubus_object_name(const char *path)
|
||||||
|
{
|
||||||
|
service_entry_t *service = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(service, ®istered_services, list) {
|
||||||
|
|
||||||
|
if (!is_path_match(path, BBFDMD_BOTH, service))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return service->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reference_data_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct blob_attr *fields[1];
|
||||||
|
const struct blobmsg_policy policy[1] = {
|
||||||
|
{ "data", BLOBMSG_TYPE_STRING },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!req || !msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *reference_data = (char *)req->priv;
|
||||||
|
|
||||||
|
if (!reference_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blobmsg_parse(policy, 1, fields, blobmsg_data(msg), blobmsg_len(msg));
|
||||||
|
|
||||||
|
if (fields[0]) {
|
||||||
|
snprintf(reference_data, MAX_PATH_LENGTH - 1, "%s", blobmsg_get_string(fields[0]));
|
||||||
|
BBFDM_DEBUG("reference_data '%s'", reference_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_reference_data(const char *path, const char *method_name)
|
||||||
|
{
|
||||||
|
struct blob_buf req_buf = {0};
|
||||||
|
char reference_value[MAX_PATH_LENGTH] = {0};
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *ubus_obj = get_ubus_object_name(path);
|
||||||
|
if (!ubus_obj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
reference_value[0] = 0;
|
||||||
|
|
||||||
|
memset(&req_buf, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&req_buf, 0);
|
||||||
|
|
||||||
|
blobmsg_add_string(&req_buf, "path", path);
|
||||||
|
|
||||||
|
if (g_log_level == LOG_DEBUG) {
|
||||||
|
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
|
||||||
|
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, method_name, json_str);
|
||||||
|
BBFDM_FREE(json_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_UBUS_INVOKE_SYNC(ubus_obj, method_name, req_buf.head, 2000, reference_data_callback, &reference_value);
|
||||||
|
|
||||||
|
blob_buf_free(&req_buf);
|
||||||
|
|
||||||
|
return (reference_value[0] != 0) ? strdup(reference_value) : NULL;
|
||||||
|
}
|
||||||
36
bbfdmd/ubus/service.h
Normal file
36
bbfdmd/ubus/service.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 iopsys Software Solutions AB
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
* as published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BBFDMD_SERVICE_H
|
||||||
|
#define BBFDMD_SERVICE_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum bbfdmd_type_enum protocol;
|
||||||
|
char parent_path[MAX_PATH_LENGTH - 256];
|
||||||
|
char object_name[256];
|
||||||
|
} service_object_t;
|
||||||
|
|
||||||
|
typedef struct service_entry {
|
||||||
|
struct list_head list;
|
||||||
|
char *name;
|
||||||
|
enum bbfdmd_type_enum protocol;
|
||||||
|
bool is_unified;
|
||||||
|
size_t object_count;
|
||||||
|
service_object_t *objects;
|
||||||
|
} service_entry_t;
|
||||||
|
|
||||||
|
int register_services(struct ubus_context *ctx);
|
||||||
|
void unregister_services(void);
|
||||||
|
void list_registered_services(struct blob_buf *bb);
|
||||||
|
|
||||||
|
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service);
|
||||||
|
|
||||||
|
#endif /* BBFDMD_SERVICE_H */
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* dm_service.c: dm-service deamon
|
* dm_service.c: dm-service deamon
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
|
* Copyright (C) 2024-2025 IOPSYS Software Solutions AB. All rights reserved.
|
||||||
*
|
*
|
||||||
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
*
|
*
|
||||||
|
|
@ -28,7 +28,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bbfdm_context bbfdm_ctx = {0};
|
struct bbfdm_context bbfdm_ctx = {0};
|
||||||
char proc_name[64] = {0};
|
char proc_name[64] = {0};
|
||||||
int log_level = 3; // Default is LOG_ERR
|
int log_level = LOG_ERR;
|
||||||
int err = 0, ch;
|
int err = 0, ch;
|
||||||
|
|
||||||
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
|
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
|
||||||
|
|
@ -53,7 +53,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dm_is_micro_service() == false) {
|
if (strlen(bbfdm_ctx.config.service_name) == 0) {
|
||||||
fprintf(stderr, "Failed to start micro-service without providing the name using '-m' option\n");
|
fprintf(stderr, "Failed to start micro-service without providing the name using '-m' option\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -742,31 +742,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"notify_event": {
|
|
||||||
"title": "notify occurance of an event on ubus",
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"input"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"input": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"input": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"output": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,10 @@ install_cmph
|
||||||
install_libeasy
|
install_libeasy
|
||||||
install_libethernet
|
install_libethernet
|
||||||
|
|
||||||
# Make sure that all plugins are removed
|
|
||||||
[ ! -d "${BBFDM_PLUGIN_DIR}" ] && mkdir -p "${BBFDM_PLUGIN_DIR}"
|
|
||||||
rm -f ${BBFDM_PLUGIN_DIR}/*
|
|
||||||
|
|
||||||
[ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}"
|
[ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}"
|
||||||
rm -f ${BBFDM_MS_DIR}/*
|
rm -rf ${BBFDM_MS_DIR}/*
|
||||||
|
|
||||||
|
mkdir -p ${BBFDM_MS_DIR}/core
|
||||||
|
|
||||||
if [ -z "${1}" ]; then
|
if [ -z "${1}" ]; then
|
||||||
./tools/generate_dm.py tools/tools_input.json
|
./tools/generate_dm.py tools/tools_input.json
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,17 @@ source ./gitlab-ci/shared.sh
|
||||||
exec_cmd apt update
|
exec_cmd apt update
|
||||||
exec_cmd pip3 install xlwt
|
exec_cmd pip3 install xlwt
|
||||||
|
|
||||||
# Make sure that all plugins are removed
|
# Create directories for micro-service configuration and shared files
|
||||||
[ ! -d "${BBFDM_PLUGIN_DIR}" ] && mkdir -p "${BBFDM_PLUGIN_DIR}"
|
[ ! -d "${BBFDM_MS_CONF}" ] && mkdir -p "${BBFDM_MS_CONF}"
|
||||||
rm -f ${BBFDM_PLUGIN_DIR}/*
|
[ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}"
|
||||||
|
|
||||||
|
# Make sure that all generated files are removed
|
||||||
|
rm -rf ${BBFDM_MS_DIR}/*
|
||||||
|
rm -f ${BBFDM_MS_CONF}/*
|
||||||
|
rm -f ${BBFDM_DMMAP_DIR}/*
|
||||||
rm -f ${BBFDM_LOG_FILE}
|
rm -f ${BBFDM_LOG_FILE}
|
||||||
|
|
||||||
# compile and install libbbf
|
# compile and install Core Data Model as a micro-service
|
||||||
install_libbbf ${1}
|
install_libbbf ${1}
|
||||||
|
|
||||||
#compile and install libbbf_test dynamic extension library
|
#compile and install libbbf_test dynamic extension library
|
||||||
|
|
@ -23,10 +28,6 @@ install_libbbf_test ${1}
|
||||||
if [ -z "${1}" ]; then
|
if [ -z "${1}" ]; then
|
||||||
echo "Skip installation of micro-services ...."
|
echo "Skip installation of micro-services ...."
|
||||||
else
|
else
|
||||||
# Create directories for micro-service configuration and shared files
|
|
||||||
mkdir -p /etc/bbfdm/services
|
|
||||||
mkdir -p /usr/share/bbfdm/micro_services
|
|
||||||
|
|
||||||
#install SYSMNGR Data Model as a micro-service
|
#install SYSMNGR Data Model as a micro-service
|
||||||
echo "Installing System Manager (SYSMNGR) Data Model as a micro-service"
|
echo "Installing System Manager (SYSMNGR) Data Model as a micro-service"
|
||||||
install_sysmngr_as_micro_service
|
install_sysmngr_as_micro_service
|
||||||
|
|
@ -39,5 +40,7 @@ else
|
||||||
echo "Installing Network Data Model (netmngr) as a micro-service"
|
echo "Installing Network Data Model (netmngr) as a micro-service"
|
||||||
install_netmngr_as_micro_service
|
install_netmngr_as_micro_service
|
||||||
|
|
||||||
|
#install Ethernet Data Model as a micro-service
|
||||||
|
echo "Installing Ethernet Data Model (ethmngr) as a micro-service"
|
||||||
install_ethmngr_as_micro_service
|
install_ethmngr_as_micro_service
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-netmngr
|
||||||
priority=7
|
priority=7
|
||||||
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-wifidmd-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/dm-service -m wifidmd"
|
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-wifidmd-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/dm-service -m wifidmd"
|
||||||
|
|
||||||
|
[program:core]
|
||||||
|
priority=8
|
||||||
|
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-core-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/dm-service -m core"
|
||||||
|
|
||||||
[program:ethmngr]
|
[program:ethmngr]
|
||||||
priority=10
|
priority=10
|
||||||
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-ethmngr-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/ethmngr"
|
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-ethmngr-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /usr/sbin/ethmngr"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ echo "# Preparation script ..."
|
||||||
# link '/bin/sh' to bash instead of dash
|
# link '/bin/sh' to bash instead of dash
|
||||||
ln -sf bash /bin/sh
|
ln -sf bash /bin/sh
|
||||||
|
|
||||||
|
#cleanup
|
||||||
|
rm -f /etc/config/*
|
||||||
|
rm -rf /tmp/bbfdm/.bbfdm/* /tmp/bbfdm/.cwmp/* /tmp/bbfdm/.usp/*
|
||||||
|
|
||||||
echo "Installing bbfdm rpcd utilities"
|
echo "Installing bbfdm rpcd utilities"
|
||||||
cp -r ./test/files/etc/* /etc/
|
cp -r ./test/files/etc/* /etc/
|
||||||
cp -r ./test/files/usr/* /usr/
|
cp -r ./test/files/usr/* /usr/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
BBFDM_PLUGIN_DIR="/usr/share/bbfdm/plugins"
|
|
||||||
BBFDM_MS_DIR="/usr/share/bbfdm/micro_services"
|
BBFDM_MS_DIR="/usr/share/bbfdm/micro_services"
|
||||||
|
BBFDM_MS_CONF="/etc/bbfdm/services"
|
||||||
|
BBFDM_DMMAP_DIR="etc/bbfdm/dmmap/"
|
||||||
BBFDM_LOG_FILE="/tmp/bbfdm.log"
|
BBFDM_LOG_FILE="/tmp/bbfdm.log"
|
||||||
|
|
||||||
if [ -z "${CI_PROJECT_PATH}" ]; then
|
if [ -z "${CI_PROJECT_PATH}" ]; then
|
||||||
|
|
@ -43,43 +44,15 @@ function exec_cmd_verbose()
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_input_schema()
|
function install_ms()
|
||||||
{
|
{
|
||||||
service_name="$1"
|
exec_cmd cp -f "${1}" ${BBFDM_MS_DIR}/${2}.so
|
||||||
schema='{
|
|
||||||
"daemon": {
|
|
||||||
"enable": "1",
|
|
||||||
"service_name": "'"$service_name"'",
|
|
||||||
"config": {
|
|
||||||
"loglevel": "4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
echo "$schema"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_input_schema_with_output_name()
|
function install_ms_plugin()
|
||||||
{
|
{
|
||||||
service_name="$1"
|
exec_cmd mkdir -p ${BBFDM_MS_DIR}/${2}
|
||||||
output_name="$2"
|
exec_cmd cp -f "${1}" ${BBFDM_MS_DIR}/${2}/
|
||||||
schema='{
|
|
||||||
"daemon": {
|
|
||||||
"enable": "1",
|
|
||||||
"service_name": "'"$service_name"'",
|
|
||||||
"config": {
|
|
||||||
"loglevel": "4"
|
|
||||||
},
|
|
||||||
"output": {
|
|
||||||
"name": "'"$output_name"'"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
echo "$schema"
|
|
||||||
}
|
|
||||||
|
|
||||||
function install_plugin()
|
|
||||||
{
|
|
||||||
exec_cmd cp -f "${1}" ${BBFDM_PLUGIN_DIR}/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_libbbf()
|
function install_libbbf()
|
||||||
|
|
@ -107,6 +80,7 @@ function install_libbbf()
|
||||||
echo "371d530c95a17d1ca223a29b7a6cdc97e1135c1e0959b51106cca91a0b148b5e42742d372a359760742803f2a44bd88fca67ccdcfaeed26d02ce3b6049cb1e04" > /etc/bbfdm/.secure_hash
|
echo "371d530c95a17d1ca223a29b7a6cdc97e1135c1e0959b51106cca91a0b148b5e42742d372a359760742803f2a44bd88fca67ccdcfaeed26d02ce3b6049cb1e04" > /etc/bbfdm/.secure_hash
|
||||||
cd ..
|
cd ..
|
||||||
exec_cmd cp utilities/bbf_configd /usr/sbin/
|
exec_cmd cp utilities/bbf_configd /usr/sbin/
|
||||||
|
install_ms /usr/lib/libcore.so core
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_libbbf_test()
|
function install_libbbf_test()
|
||||||
|
|
@ -117,21 +91,17 @@ function install_libbbf_test()
|
||||||
exec_cmd_verbose make -C test/bbf_test/
|
exec_cmd_verbose make -C test/bbf_test/
|
||||||
|
|
||||||
echo "installing libbbf_test"
|
echo "installing libbbf_test"
|
||||||
install_plugin ./test/bbf_test/libbbf_test.so
|
install_ms_plugin ./test/bbf_test/libbbf_test.so core
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_wifidmd_as_micro_service()
|
function install_wifidmd_as_micro_service()
|
||||||
{
|
{
|
||||||
[ -d "/opt/dev/wifidmd" ] && return 0
|
[ -d "/opt/dev/wifidmd" ] && return 0
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/bbf/wifidmd.git /opt/dev/wifidmd
|
exec_cmd git clone -b devel https://dev.iopsys.eu/bbf/wifidmd.git /opt/dev/wifidmd
|
||||||
|
|
||||||
exec_cmd make -C /opt/dev/wifidmd/src/ clean && make -C /opt/dev/wifidmd/src/ CFLAGS="-D'BBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"'"
|
exec_cmd make -C /opt/dev/wifidmd/src/ clean && make -C /opt/dev/wifidmd/src/ CFLAGS="-D'BBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"'" WIFIDMD_WIFI_DATAELEMENTS='y'
|
||||||
exec_cmd cp -f /opt/dev/wifidmd/src/libwifi.so /usr/share/bbfdm/micro_services/wifidmd.so
|
install_ms /opt/dev/wifidmd/src/libwifi.so wifidmd
|
||||||
exec_cmd mkdir -p /usr/share/bbfdm/micro_services/wifidmd
|
|
||||||
exec_cmd cp -f /opt/dev/wifidmd/src/libdataelements.so /usr/share/bbfdm/micro_services/wifidmd
|
|
||||||
|
|
||||||
generate_input_schema_with_output_name "wifidmd" "WiFi" > /etc/bbfdm/services/wifidmd.json
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_libeasy()
|
function install_libeasy()
|
||||||
|
|
@ -172,45 +142,45 @@ function install_ethmngr_as_micro_service()
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/hal/ethmngr.git /opt/dev/ethmngr
|
exec_cmd git clone https://dev.iopsys.eu/hal/ethmngr.git /opt/dev/ethmngr
|
||||||
exec_cmd make -C /opt/dev/ethmngr
|
exec_cmd make -C /opt/dev/ethmngr
|
||||||
exec_cmd cp /opt/dev/ethmngr/ethmngr /usr/sbin/ethmngr
|
exec_cmd cp -f /opt/dev/ethmngr/ethmngr /usr/sbin/ethmngr
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_netmngr_as_micro_service()
|
function install_netmngr_as_micro_service()
|
||||||
{
|
{
|
||||||
[ -d "/opt/dev/netmngr" ] && return 0
|
[ -d "/opt/dev/netmngr" ] && return 0
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/network/netmngr.git /opt/dev/netmngr
|
exec_cmd git clone -b devel https://dev.iopsys.eu/network/netmngr.git /opt/dev/netmngr
|
||||||
|
|
||||||
|
exec_cmd apt install iproute2 -y
|
||||||
|
|
||||||
exec_cmd make -C /opt/dev/netmngr/src/ clean
|
exec_cmd make -C /opt/dev/netmngr/src/ clean
|
||||||
exec_cmd make -C /opt/dev/netmngr/src/ NETMNGR_GRE_OBJ=y NETMNGR_IP_OBJ=y NETMNGR_ROUTING_OBJ=y NETMNGR_PPP_OBJ=y NETMNGR_ROUTER_ADVERTISEMENT_OBJ=y NETMNGR_IPV6RD_OBJ=y
|
exec_cmd make -C /opt/dev/netmngr/src/ NETMNGR_GRE_OBJ=y NETMNGR_IP_OBJ=y NETMNGR_ROUTING_OBJ=y NETMNGR_PPP_OBJ=y NETMNGR_ROUTER_ADVERTISEMENT_OBJ=y NETMNGR_IPV6RD_OBJ=y
|
||||||
exec_cmd cp -f /opt/dev/netmngr/src/libnetmngr.so /usr/share/bbfdm/micro_services/netmngr.so
|
install_ms /opt/dev/netmngr/src/libnetmngr.so netmngr
|
||||||
exec_cmd cp -f /opt/dev/netmngr/src/libinterface_stack.so /usr/share/bbfdm/plugins
|
|
||||||
exec_cmd mkdir -p /usr/share/bbfdm/micro_services/netmngr
|
|
||||||
|
|
||||||
generate_input_schema_with_output_name "netmngr" "Network" > /etc/bbfdm/services/netmngr.json
|
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/bbf/tr143d.git /opt/dev/tr143d
|
exec_cmd git clone https://dev.iopsys.eu/bbf/tr143d.git /opt/dev/tr143d
|
||||||
exec_cmd make -C /opt/dev/tr143d/src/ clean && make -C /opt/dev/tr143d/src/
|
exec_cmd make -C /opt/dev/tr143d/src/ clean && make -C /opt/dev/tr143d/src/
|
||||||
exec_cmd cp -f /opt/dev/tr143d/src/libtr143d.so /usr/share/bbfdm/micro_services/netmngr
|
exec_cmd cp -f utilities/files/usr/share/bbfdm/scripts/bbf_api /usr/share/bbfdm/scripts/
|
||||||
|
exec_cmd cp -rf /opt/dev/tr143d/scripts/* /usr/share/bbfdm/scripts/
|
||||||
|
install_ms_plugin /opt/dev/tr143d/src/libtr143d.so netmngr
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/bbf/tr471d.git /opt/dev/tr471d
|
exec_cmd git clone https://dev.iopsys.eu/bbf/tr471d.git /opt/dev/tr471d
|
||||||
exec_cmd make -C /opt/dev/tr471d/src/ clean && make -C /opt/dev/tr471d/src/
|
exec_cmd make -C /opt/dev/tr471d/src/ clean && make -C /opt/dev/tr471d/src/
|
||||||
exec_cmd cp -f /opt/dev/tr471d/src/libtr471d.so /usr/share/bbfdm/micro_services/netmngr
|
install_ms_plugin /opt/dev/tr471d/src/libtr471d.so netmngr
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/bbf/twamp-light.git /opt/dev/twamp
|
exec_cmd git clone https://dev.iopsys.eu/bbf/twamp-light.git /opt/dev/twamp
|
||||||
exec_cmd make -C /opt/dev/twamp clean && make -C /opt/dev/twamp
|
exec_cmd make -C /opt/dev/twamp clean && make -C /opt/dev/twamp
|
||||||
exec_cmd cp -f /opt/dev/twamp/libtwamp.so /usr/share/bbfdm/micro_services/netmngr
|
install_ms_plugin /opt/dev/twamp/libtwamp.so netmngr
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/bbf/udpecho.git /opt/dev/udpecho
|
exec_cmd git clone https://dev.iopsys.eu/bbf/udpecho.git /opt/dev/udpecho
|
||||||
exec_cmd make -C /opt/dev/udpecho/src/ clean && make -C /opt/dev/udpecho/src/
|
exec_cmd make -C /opt/dev/udpecho/src/ clean && make -C /opt/dev/udpecho/src/
|
||||||
exec_cmd cp -f /opt/dev/udpecho/src/libudpechoserver.so /usr/share/bbfdm/micro_services/netmngr
|
install_ms_plugin /opt/dev/udpecho/src/libudpechoserver.so netmngr
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_sysmngr_as_micro_service()
|
function install_sysmngr_as_micro_service()
|
||||||
{
|
{
|
||||||
[ -d "/opt/dev/sysmngr" ] && return 0
|
[ -d "/opt/dev/sysmngr" ] && return 0
|
||||||
|
|
||||||
exec_cmd git clone https://dev.iopsys.eu/system/sysmngr.git /opt/dev/sysmngr
|
exec_cmd git clone -b devel https://dev.iopsys.eu/system/sysmngr.git /opt/dev/sysmngr
|
||||||
|
|
||||||
exec_cmd make -C /opt/dev/sysmngr/src/ clean && \
|
exec_cmd make -C /opt/dev/sysmngr/src/ clean && \
|
||||||
exec_cmd make -C /opt/dev/sysmngr/src/ \
|
exec_cmd make -C /opt/dev/sysmngr/src/ \
|
||||||
|
|
@ -225,7 +195,7 @@ function install_sysmngr_as_micro_service()
|
||||||
SYSMNGR_VENDOR_EXTENSIONS='y' \
|
SYSMNGR_VENDOR_EXTENSIONS='y' \
|
||||||
SYSMNGR_FWBANK_UBUS_SUPPORT='y'
|
SYSMNGR_FWBANK_UBUS_SUPPORT='y'
|
||||||
|
|
||||||
exec_cmd cp /opt/dev/sysmngr/src/sysmngr /usr/sbin/
|
exec_cmd cp -f /opt/dev/sysmngr/src/sysmngr /usr/sbin/
|
||||||
exec_cmd mkdir /etc/sysmngr
|
exec_cmd mkdir /etc/sysmngr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ echo "Validate BBF Data Model JSON Plugin"
|
||||||
check_ret $?
|
check_ret $?
|
||||||
|
|
||||||
echo "Validating plugins"
|
echo "Validating plugins"
|
||||||
for plugin in $(ls -1 test/files/usr/share/bbfdm/plugins/*); do
|
for plugin in $(ls -1 test/files/usr/share/bbfdm/micro_services/core/*); do
|
||||||
echo "Validating ${plugin} JSON Plugin"
|
echo "Validating ${plugin} JSON Plugin"
|
||||||
./tools/validate_json_plugin.py ${plugin}
|
./tools/validate_json_plugin.py ${plugin}
|
||||||
check_ret $?
|
check_ret $?
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,22 @@ int bbf_set_alias(struct dmctx *ctx, struct uci_section *s, const char *option_n
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void send_linker_request_event(struct ubus_context *ctx, const char *path)
|
||||||
|
{
|
||||||
|
struct blob_buf bb;
|
||||||
|
|
||||||
|
if (DM_STRLEN(path) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
|
||||||
|
blobmsg_add_string(&bb, "path", path);
|
||||||
|
|
||||||
|
ubus_send_event(ctx, "bbfdm.linker.request", bb.head);
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
}
|
||||||
|
|
||||||
int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_path, const char *key_name, char *key_value, char *out, size_t out_len)
|
int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_path, const char *key_name, char *key_value, char *out, size_t out_len)
|
||||||
{
|
{
|
||||||
char param_path[1024] = {0};
|
char param_path[1024] = {0};
|
||||||
|
|
@ -261,20 +277,20 @@ int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_p
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", value);
|
snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", value);
|
||||||
goto end;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dm_is_micro_service() == true) { // It's a micro-service instance
|
|
||||||
|
|
||||||
if (out_len - len < strlen(base_path) + strlen(key_name) + strlen(key_value) + 9) { // 9 = 'path[key_name==\"key_value\"].'
|
if (out_len - len < strlen(base_path) + strlen(key_name) + strlen(key_value) + 9) { // 9 = 'path[key_name==\"key_value\"].'
|
||||||
BBF_ERR("Buffer overflow detected. The output buffer is not large enough to hold the additional data!!!");
|
BBF_ERR("Buffer overflow detected. The output buffer is not large enough to hold the additional data!!!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(&out[len], out_len - len, "%s%s[%s==\"%s\"].", len ? (match_action == MATCH_FIRST ? "," : ";") : "", base_path, key_name, key_value);
|
snprintf(param_path, sizeof(param_path), "%s[%s==\"%s\"].", base_path, key_name, key_value);
|
||||||
}
|
|
||||||
|
send_linker_request_event(ctx->ubus_ctx, param_path);
|
||||||
|
|
||||||
|
snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", param_path);
|
||||||
|
|
||||||
end:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -317,68 +333,6 @@ int bbfdm_get_reference_linker(struct dmctx *ctx, char *reference_path, struct d
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *bbfdm_get_reference_value(const char *reference_path)
|
|
||||||
{
|
|
||||||
unsigned int reference_path_dot_num = count_occurrences(reference_path, '.');
|
|
||||||
json_object *res = NULL;
|
|
||||||
|
|
||||||
json_object *in_args = json_object_new_object();
|
|
||||||
json_object_object_add(in_args, "proto", json_object_new_string("usp"));
|
|
||||||
json_object_object_add(in_args, "format", json_object_new_string("raw"));
|
|
||||||
|
|
||||||
dmubus_call("bbfdm", "get",
|
|
||||||
UBUS_ARGS{
|
|
||||||
{"path", reference_path, String},
|
|
||||||
{"optional", json_object_to_json_string(in_args), Table}
|
|
||||||
},
|
|
||||||
2, &res);
|
|
||||||
|
|
||||||
json_object_put(in_args);
|
|
||||||
|
|
||||||
if (!res)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
json_object *res_array = dmjson_get_obj(res, 1, "results");
|
|
||||||
if (!res_array)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
size_t nbre_obj = json_object_array_length(res_array);
|
|
||||||
if (nbre_obj == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nbre_obj; i++) {
|
|
||||||
json_object *res_obj = json_object_array_get_idx(res_array, i);
|
|
||||||
|
|
||||||
char *fault = dmjson_get_value(res_obj, 1, "fault");
|
|
||||||
if (DM_STRLEN(fault))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char *path = dmjson_get_value(res_obj, 1, "path");
|
|
||||||
|
|
||||||
unsigned int path_dot_num = count_occurrences(path, '.');
|
|
||||||
if (path_dot_num > reference_path_dot_num)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
json_object *flags_array = dmjson_get_obj(res_obj, 1, "flags");
|
|
||||||
if (flags_array) {
|
|
||||||
size_t nbre_falgs = json_object_array_length(flags_array);
|
|
||||||
|
|
||||||
for (size_t j = 0; j < nbre_falgs; j++) {
|
|
||||||
json_object *flag_obj = json_object_array_get_idx(flags_array, j);
|
|
||||||
|
|
||||||
const char *flag = json_object_get_string(flag_obj);
|
|
||||||
|
|
||||||
if (DM_LSTRCMP(flag, "Linker") == 0) {
|
|
||||||
char *data = dmjson_get_value(res_obj, 1, "data");
|
|
||||||
return data ? dmstrdup(data) : "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path, char **reference_value)
|
int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path, char **reference_value)
|
||||||
{
|
{
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
|
|
@ -401,8 +355,5 @@ int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path
|
||||||
if (DM_STRLEN(*reference_value) != 0)
|
if (DM_STRLEN(*reference_value) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dm_is_micro_service() == true) // It's a micro-service instance
|
|
||||||
*reference_value = bbfdm_get_reference_value(reference_path);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include "libbbfdm-api/version-2/bbfdm_api.h"
|
#include "libbbfdm-api/version-2/bbfdm_api.h"
|
||||||
|
|
||||||
|
#define ROOT_NODE "Device."
|
||||||
|
|
||||||
extern struct dm_permession_s DMREAD;
|
extern struct dm_permession_s DMREAD;
|
||||||
extern struct dm_permession_s DMWRITE;
|
extern struct dm_permession_s DMWRITE;
|
||||||
extern struct dm_permession_s DMSYNC;
|
extern struct dm_permession_s DMSYNC;
|
||||||
|
|
@ -177,21 +179,12 @@ struct dmctx {
|
||||||
bool iscommand;
|
bool iscommand;
|
||||||
bool isevent;
|
bool isevent;
|
||||||
bool isinfo;
|
bool isinfo;
|
||||||
bool disable_mservice_browse;
|
|
||||||
|
|
||||||
int (*method_param)(DMPARAM_ARGS);
|
int (*method_param)(DMPARAM_ARGS);
|
||||||
int (*method_obj)(DMOBJECT_ARGS);
|
int (*method_obj)(DMOBJECT_ARGS);
|
||||||
int (*checkobj)(DMOBJECT_ARGS);
|
int (*checkobj)(DMOBJECT_ARGS);
|
||||||
int (*checkleaf)(DMOBJECT_ARGS);
|
int (*checkleaf)(DMOBJECT_ARGS);
|
||||||
|
|
||||||
struct list_head *memhead;
|
|
||||||
struct blob_buf bb;
|
|
||||||
|
|
||||||
DMOBJ *dm_entryobj;
|
|
||||||
struct uci_context *config_uci_ctx;
|
|
||||||
struct uci_context *dmmap_uci_ctx;
|
|
||||||
struct uci_context *varstate_uci_ctx;
|
|
||||||
|
|
||||||
int faultcode;
|
int faultcode;
|
||||||
int setaction;
|
int setaction;
|
||||||
unsigned int dm_type;
|
unsigned int dm_type;
|
||||||
|
|
@ -204,6 +197,16 @@ struct dmctx {
|
||||||
char *addobj_instance;
|
char *addobj_instance;
|
||||||
char *linker;
|
char *linker;
|
||||||
char *linker_param;
|
char *linker_param;
|
||||||
|
|
||||||
|
struct blob_buf bb;
|
||||||
|
|
||||||
|
DMOBJ *dm_entryobj;
|
||||||
|
struct uci_context *config_uci_ctx;
|
||||||
|
struct uci_context *dmmap_uci_ctx;
|
||||||
|
struct uci_context *varstate_uci_ctx;
|
||||||
|
struct ubus_context *ubus_ctx;
|
||||||
|
struct list_head *memhead;
|
||||||
|
|
||||||
char *inst_buf[16];
|
char *inst_buf[16];
|
||||||
char fault_msg[256];
|
char fault_msg[256];
|
||||||
};
|
};
|
||||||
|
|
@ -220,7 +223,6 @@ typedef struct dmnode {
|
||||||
unsigned char browse_type;
|
unsigned char browse_type;
|
||||||
int max_instance;
|
int max_instance;
|
||||||
int num_of_entries;
|
int num_of_entries;
|
||||||
bool is_ubus_service;
|
|
||||||
} DMNODE;
|
} DMNODE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -387,7 +389,6 @@ enum bbfdm_type_enum {
|
||||||
enum {
|
enum {
|
||||||
INDX_JSON_MOUNT,
|
INDX_JSON_MOUNT,
|
||||||
INDX_LIBRARY_MOUNT,
|
INDX_LIBRARY_MOUNT,
|
||||||
INDX_SERVICE_MOUNT,
|
|
||||||
__INDX_DYNAMIC_MAX
|
__INDX_DYNAMIC_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,9 +27,6 @@
|
||||||
#include "dmmem.h"
|
#include "dmmem.h"
|
||||||
#include "dmapi.h"
|
#include "dmapi.h"
|
||||||
|
|
||||||
bool dm_is_micro_service(void);
|
|
||||||
void dm_set_micro_service(void);
|
|
||||||
|
|
||||||
int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance));
|
int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance));
|
||||||
char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt);
|
char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt);
|
||||||
char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr);
|
char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr);
|
||||||
|
|
@ -40,7 +37,6 @@ void fill_blob_event(struct blob_buf *bb, const char *path, const char *type, vo
|
||||||
void fill_blob_operate(struct blob_buf *bb, const char *path, const char *data, const char *type, void *in_out);
|
void fill_blob_operate(struct blob_buf *bb, const char *path, const char *data, const char *type, void *in_out);
|
||||||
|
|
||||||
int string_to_bool(const char *v, bool *b);
|
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(struct dmctx *dmctx);
|
||||||
int dm_entry_get_name(struct dmctx *ctx);
|
int dm_entry_get_name(struct dmctx *ctx);
|
||||||
int dm_entry_get_supported_dm(struct dmctx *ctx);
|
int dm_entry_get_supported_dm(struct dmctx *ctx);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ void bbf_ctx_init(struct dmctx *ctx, DMOBJ *tEntryObj)
|
||||||
ctx->dm_entryobj = tEntryObj;
|
ctx->dm_entryobj = tEntryObj;
|
||||||
dm_init_mem(ctx);
|
dm_init_mem(ctx);
|
||||||
dm_uci_init(ctx);
|
dm_uci_init(ctx);
|
||||||
|
dm_ubus_init(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bbf_ctx_clean(struct dmctx *ctx)
|
void bbf_ctx_clean(struct dmctx *ctx)
|
||||||
|
|
@ -57,7 +58,7 @@ void bbf_ctx_clean(struct dmctx *ctx)
|
||||||
|
|
||||||
dm_uci_exit(ctx);
|
dm_uci_exit(ctx);
|
||||||
dm_clean_mem(ctx);
|
dm_clean_mem(ctx);
|
||||||
dmubus_free();
|
dm_ubus_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bbf_ctx_init_sub(struct dmctx *ctx, DMOBJ *tEntryObj)
|
void bbf_ctx_init_sub(struct dmctx *ctx, DMOBJ *tEntryObj)
|
||||||
|
|
@ -273,13 +274,10 @@ int adm_entry_get_reference_param(struct dmctx *ctx, char *param, char *linker,
|
||||||
{
|
{
|
||||||
struct dmctx dmctx = {0};
|
struct dmctx dmctx = {0};
|
||||||
|
|
||||||
*value = dmstrdup("");
|
if (DM_STRLEN(param) == 0 || DM_STRLEN(linker) == 0)
|
||||||
|
|
||||||
if (!param || !linker || *linker == 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bbf_ctx_init_sub(&dmctx, ctx->dm_entryobj);
|
dmctx.dm_entryobj = ctx->dm_entryobj;
|
||||||
|
|
||||||
dmctx.iswildcard = 1;
|
dmctx.iswildcard = 1;
|
||||||
dmctx.inparam_isparam = 1;
|
dmctx.inparam_isparam = 1;
|
||||||
dmctx.in_param = param;
|
dmctx.in_param = param;
|
||||||
|
|
@ -287,9 +285,8 @@ int adm_entry_get_reference_param(struct dmctx *ctx, char *param, char *linker,
|
||||||
|
|
||||||
dm_entry_get_reference_param(&dmctx);
|
dm_entry_get_reference_param(&dmctx);
|
||||||
|
|
||||||
*value = dmctx.linker_param ? dmctx.linker_param : dmstrdup("");
|
*value = dmctx.linker_param;
|
||||||
|
|
||||||
bbf_ctx_clean_sub(&dmctx);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -317,7 +314,7 @@ int adm_entry_get_reference_value(struct dmctx *ctx, const char *param, char **v
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool adm_entry_object_exists(struct dmctx *ctx, const char *param) // To be removed later!!!!!!!!!!!! (After moving all Objects outside bbfdm core)
|
bool adm_entry_object_exists(struct dmctx *ctx, const char *param) // To be removed later
|
||||||
{
|
{
|
||||||
struct dmctx dmctx = {0};
|
struct dmctx dmctx = {0};
|
||||||
char linker[256] = {0};
|
char linker[256] = {0};
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,8 @@ void bbf_global_clean(DMOBJ *dm_entryobj);
|
||||||
|
|
||||||
int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *reference, char *objects[]);
|
int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *reference, char *objects[]);
|
||||||
|
|
||||||
bool adm_entry_object_exists(struct dmctx *ctx, const char *param); // To be removed later!!!!!!!!!!!! (After moving all Objects outside bbfdm core)
|
bool adm_entry_object_exists(struct dmctx *ctx, const char *param); // To be removed later
|
||||||
|
|
||||||
void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required);
|
void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required);
|
||||||
|
|
||||||
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb);
|
|
||||||
bool load_service(DMOBJ *main_dm, struct list_head *srv_list, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, bool is_unified, uint8_t proto);
|
|
||||||
void free_services_from_list(struct list_head *clist);
|
|
||||||
|
|
||||||
#endif //__DMENTRY_H__
|
#endif //__DMENTRY_H__
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 iopsys Software Solutions AB
|
* Copyright (C) 2023-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
|
@ -14,141 +14,6 @@
|
||||||
#include "plugin/json_plugin.h"
|
#include "plugin/json_plugin.h"
|
||||||
#include "plugin/dotso_plugin.h"
|
#include "plugin/dotso_plugin.h"
|
||||||
|
|
||||||
extern struct list_head global_memhead;
|
|
||||||
|
|
||||||
struct service
|
|
||||||
{
|
|
||||||
bool is_unified_daemon;
|
|
||||||
enum bbfdm_type_enum proto;
|
|
||||||
struct list_head list;
|
|
||||||
char *name;
|
|
||||||
char *parent_dm;
|
|
||||||
char *object;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool add_service_to_main_tree(DMOBJ *main_dm, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, uint8_t proto)
|
|
||||||
{
|
|
||||||
DMOBJ *dm_entryobj = find_entry_obj(main_dm, srv_parent_dm);
|
|
||||||
if (!dm_entryobj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Disable service object if it already exists in the main tree
|
|
||||||
disable_entry_obj(dm_entryobj, srv_obj, srv_parent_dm, srv_name);
|
|
||||||
|
|
||||||
if (dm_entryobj->nextdynamicobj == NULL) {
|
|
||||||
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj == NULL) {
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj = calloc(2, sizeof(DMOBJ *));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] == NULL) {
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] = dm_dynamic_calloc(&global_memhead, 2, sizeof(struct dm_obj_s));
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).obj = dm_dynamic_strdup(&global_memhead, srv_obj);
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).checkdep = dm_dynamic_strdup(&global_memhead, srv_name);
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).bbfdm_type = proto;
|
|
||||||
} else {
|
|
||||||
int idx = get_entry_obj_idx(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0]);
|
|
||||||
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] = dm_dynamic_realloc(&global_memhead, dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0], (idx + 2) * sizeof(struct dm_obj_s));
|
|
||||||
memset(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s));
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).obj = dm_dynamic_strdup(&global_memhead, srv_obj);
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).checkdep = dm_dynamic_strdup(&global_memhead, srv_name);
|
|
||||||
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).bbfdm_type = proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_service_registered(struct list_head *srvlist, const char *srv_name, const char *srv_parent_dm, const char *srv_obj)
|
|
||||||
{
|
|
||||||
struct service *srv = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry(srv, srvlist, list) {
|
|
||||||
if (DM_STRCMP(srv->name, srv_name) == 0 &&
|
|
||||||
DM_STRCMP(srv->parent_dm, srv_parent_dm) == 0 &&
|
|
||||||
DM_STRCMP(srv->object, srv_obj) == 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_service_to_list(struct list_head *srvlist, const char *srv_name, const char *srv_parent_dm, const char *srv_object, uint8_t proto, bool is_unified)
|
|
||||||
{
|
|
||||||
struct service *srv = NULL;
|
|
||||||
|
|
||||||
srv = calloc(1, sizeof(struct service));
|
|
||||||
list_add_tail(&srv->list, srvlist);
|
|
||||||
|
|
||||||
srv->name = strdup(srv_name);
|
|
||||||
srv->parent_dm = strdup(srv_parent_dm);
|
|
||||||
srv->object = strdup(srv_object);
|
|
||||||
srv->is_unified_daemon = is_unified;
|
|
||||||
srv->proto = proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_services_from_list(struct list_head *clist)
|
|
||||||
{
|
|
||||||
struct service *srv = NULL, *tmp = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(srv, tmp, clist, list) {
|
|
||||||
list_del(&srv->list);
|
|
||||||
free(srv->name);
|
|
||||||
free(srv->parent_dm);
|
|
||||||
free(srv->object);
|
|
||||||
free(srv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool load_service(DMOBJ *main_dm, struct list_head *srv_list, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, bool is_unified, uint8_t proto)
|
|
||||||
{
|
|
||||||
if (!main_dm || !srv_list || !srv_name || !srv_parent_dm || !srv_obj) {
|
|
||||||
BBF_ERR("Invalid arguments: main_dm, srv_list, srv_name, srv_parent_dm, and srv_obj must not be NULL.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_service_registered(srv_list, srv_name, srv_parent_dm, srv_obj)) {
|
|
||||||
BBF_DEBUG("Service registration failed: Service '%s' with parent DM '%s' and object '%s' is already registered.",
|
|
||||||
srv_name, srv_parent_dm, srv_obj);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!add_service_to_main_tree(main_dm, srv_name, srv_parent_dm, srv_obj, proto)) {
|
|
||||||
BBF_ERR("Failed to add service '%s' to main tree with parent DM '%s' and object '%s'.",
|
|
||||||
srv_name, srv_parent_dm, srv_obj);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_service_to_list(srv_list, srv_name, srv_parent_dm, srv_obj, proto, is_unified);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb)
|
|
||||||
{
|
|
||||||
struct service *srv = NULL;
|
|
||||||
void *table = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry(srv, srvlist, list) {
|
|
||||||
table = blobmsg_open_table(bb, NULL);
|
|
||||||
blobmsg_add_string(bb, "name", srv->name);
|
|
||||||
blobmsg_add_string(bb, "parent_dm", srv->parent_dm);
|
|
||||||
blobmsg_add_string(bb, "object", srv->object);
|
|
||||||
if (srv->proto == BBFDM_USP) {
|
|
||||||
blobmsg_add_string(bb, "proto", "usp");
|
|
||||||
} else if (srv->proto == BBFDM_CWMP) {
|
|
||||||
blobmsg_add_string(bb, "proto", "cwmp");
|
|
||||||
} else {
|
|
||||||
blobmsg_add_string(bb, "proto", "both");
|
|
||||||
}
|
|
||||||
blobmsg_add_u8(bb, "unified_daemon", srv->is_unified_daemon);
|
|
||||||
blobmsg_close_table(bb, table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_all_dynamic_nodes(DMOBJ *entryobj)
|
static void free_all_dynamic_nodes(DMOBJ *entryobj)
|
||||||
{
|
{
|
||||||
for (; (entryobj && entryobj->obj); entryobj++) {
|
for (; (entryobj && entryobj->obj); entryobj++) {
|
||||||
|
|
@ -356,47 +221,45 @@ int get_leaf_idx(DMLEAF **entryleaf)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int filter(const struct dirent *entry)
|
||||||
|
{
|
||||||
|
return entry->d_name[0] != '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare(const struct dirent **a, const struct dirent **b)
|
||||||
|
{
|
||||||
|
return strcasecmp((*a)->d_name, (*b)->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
|
void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
|
||||||
{
|
{
|
||||||
|
struct dirent **namelist;
|
||||||
|
|
||||||
if (DM_STRLEN(plugin_path) == 0) // If empty, return without further action
|
if (DM_STRLEN(plugin_path) == 0) // If empty, return without further action
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!folder_exists(plugin_path)) {
|
if (!folder_exists(plugin_path)) {
|
||||||
BBF_ERR("(%s) doesn't exist", plugin_path);
|
BBF_ERR("Folder plugin (%s) doesn't exist", plugin_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dirent *ent = NULL;
|
int num_files = scandir(plugin_path, &namelist, filter, compare);
|
||||||
int num_files = 0;
|
|
||||||
char *files[256];
|
|
||||||
|
|
||||||
DIR *dir = opendir(plugin_path);
|
|
||||||
if (dir == NULL) {
|
|
||||||
BBF_ERR("Cannot open (%s) directory", plugin_path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = readdir(dir)) != NULL && num_files < 256) {
|
|
||||||
files[num_files++] = strdup(ent->d_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
qsort(files, num_files, sizeof(char *), compare_strings);
|
|
||||||
|
|
||||||
for (int i = 0; i < num_files; i++) {
|
for (int i = 0; i < num_files; i++) {
|
||||||
char buf[512] = {0};
|
char file_path[512] = {0};
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", plugin_path, files[i]);
|
snprintf(file_path, sizeof(file_path), "%s/%s", plugin_path, namelist[i]->d_name);
|
||||||
|
|
||||||
if (DM_LSTRSTR(files[i], ".json")) {
|
if (DM_LSTRSTR(namelist[i]->d_name, ".json")) {
|
||||||
load_json_plugins(dm_entryobj, buf);
|
load_json_plugins(dm_entryobj, file_path);
|
||||||
} else if (DM_LSTRSTR(files[i], ".so")) {
|
} else if (DM_LSTRSTR(namelist[i]->d_name, ".so")) {
|
||||||
load_dotso_plugins(dm_entryobj, buf);
|
load_dotso_plugins(dm_entryobj, file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(files[i]);
|
FREE(namelist[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FREE(namelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_plugins(DMOBJ *dm_entryobj)
|
void free_plugins(DMOBJ *dm_entryobj)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 iopsys Software Solutions AB
|
* Copyright (C) 2023-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,6 @@ static json_object *json_res = NULL;
|
||||||
|
|
||||||
static const struct dm_ubus_cache_entry * dm_ubus_cache_lookup(unsigned hash);
|
static const struct dm_ubus_cache_entry * dm_ubus_cache_lookup(unsigned hash);
|
||||||
|
|
||||||
static struct ubus_context *dm_libubus_init()
|
|
||||||
{
|
|
||||||
return ubus_connect(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dm_libubus_free()
|
|
||||||
{
|
|
||||||
if (ubus_ctx) {
|
|
||||||
ubus_free(ubus_ctx);
|
|
||||||
ubus_ctx = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prepare_blob_message(struct blob_buf *b, const struct ubus_arg u_args[], int u_args_size)
|
static void prepare_blob_message(struct blob_buf *b, const struct ubus_arg u_args[], int u_args_size)
|
||||||
{
|
{
|
||||||
if (!b)
|
if (!b)
|
||||||
|
|
@ -102,13 +89,10 @@ static int __dm_ubus_call_internal(const char *obj, const char *method, int time
|
||||||
|
|
||||||
json_res = NULL;
|
json_res = NULL;
|
||||||
|
|
||||||
if (ubus_ctx == NULL) {
|
|
||||||
ubus_ctx = dm_libubus_init();
|
|
||||||
if (ubus_ctx == NULL) {
|
if (ubus_ctx == NULL) {
|
||||||
BBF_ERR("UBUS context is null");
|
BBF_ERR("UBUS context is null");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ubus_lookup_id(ubus_ctx, obj, &id)) {
|
if (ubus_lookup_id(ubus_ctx, obj, &id)) {
|
||||||
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
|
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
|
||||||
|
|
@ -332,12 +316,9 @@ static int dmubus_call_blob_internal(const char *obj, const char *method, json_o
|
||||||
if (resp) *resp = NULL;
|
if (resp) *resp = NULL;
|
||||||
|
|
||||||
if (ubus_ctx == NULL) {
|
if (ubus_ctx == NULL) {
|
||||||
ubus_ctx = dm_libubus_init();
|
BBF_ERR("UBUS context is null");
|
||||||
if (ubus_ctx == NULL) {
|
|
||||||
printf("UBUS context is null\n\r");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
memset(&blob, 0, sizeof(struct blob_buf));
|
memset(&blob, 0, sizeof(struct blob_buf));
|
||||||
blob_buf_init(&blob, 0);
|
blob_buf_init(&blob, 0);
|
||||||
|
|
@ -387,20 +368,17 @@ int dmubus_call_blob_set(const char *obj, const char *method, json_object *value
|
||||||
static int dmubus_call_blob_msg_internal(const char *obj, const char *method, struct blob_buf *data, int timeout, json_object **resp)
|
static int dmubus_call_blob_msg_internal(const char *obj, const char *method, struct blob_buf *data, int timeout, json_object **resp)
|
||||||
{
|
{
|
||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
int rc = -1;
|
int rc;
|
||||||
|
|
||||||
json_res = NULL;
|
json_res = NULL;
|
||||||
|
|
||||||
if (resp)
|
if (resp)
|
||||||
*resp = NULL;
|
*resp = NULL;
|
||||||
|
|
||||||
if (ubus_ctx == NULL) {
|
|
||||||
ubus_ctx = dm_libubus_init();
|
|
||||||
if (ubus_ctx == NULL) {
|
if (ubus_ctx == NULL) {
|
||||||
BBF_ERR("UBUS context is null");
|
BBF_ERR("UBUS context is null");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ubus_lookup_id(ubus_ctx, obj, &id)) {
|
if (ubus_lookup_id(ubus_ctx, obj, &id)) {
|
||||||
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
|
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
|
||||||
|
|
@ -533,8 +511,8 @@ int dmubus_call(const char *obj, const char *method, struct ubus_arg u_args[], i
|
||||||
|
|
||||||
int dmubus_call_blocking(const char *obj, const char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res)
|
int dmubus_call_blocking(const char *obj, const char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
struct blob_buf bmsg;
|
struct blob_buf bmsg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
memset(&bmsg, 0, sizeof(struct blob_buf));
|
memset(&bmsg, 0, sizeof(struct blob_buf));
|
||||||
prepare_blob_message(&bmsg, u_args, u_args_size);
|
prepare_blob_message(&bmsg, u_args, u_args_size);
|
||||||
|
|
@ -578,8 +556,7 @@ bool dmubus_object_method_exists(const char *object)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ubus_ctx == NULL) {
|
if (ubus_ctx == NULL) {
|
||||||
ubus_ctx = dm_libubus_init();
|
BBF_ERR("UBUS context is null");
|
||||||
if (ubus_ctx == NULL)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -601,8 +578,17 @@ bool dmubus_object_method_exists(const char *object)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmubus_free()
|
void dm_ubus_init(struct dmctx *bbf_ctx)
|
||||||
|
{
|
||||||
|
bbf_ctx->ubus_ctx = ubus_ctx = ubus_connect(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dm_ubus_free(struct dmctx *bbf_ctx)
|
||||||
{
|
{
|
||||||
dm_ubus_cache_entry_free();
|
dm_ubus_cache_entry_free();
|
||||||
dm_libubus_free();
|
|
||||||
|
if (bbf_ctx->ubus_ctx) {
|
||||||
|
ubus_free(bbf_ctx->ubus_ctx);
|
||||||
|
bbf_ctx->ubus_ctx = ubus_ctx = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ int dmubus_call_blob_set(const char *obj, const char *method, json_object *value
|
||||||
|
|
||||||
int dmubus_call_blob_msg_set(const char *obj, const char *method, struct blob_buf *blob_msg);
|
int dmubus_call_blob_msg_set(const char *obj, const char *method, struct blob_buf *blob_msg);
|
||||||
|
|
||||||
void dmubus_free();
|
void dm_ubus_init(struct dmctx *bbf_ctx);
|
||||||
|
void dm_ubus_free(struct dmctx *bbf_ctx);
|
||||||
|
|
||||||
bool dmubus_object_method_exists(const char *obj);
|
bool dmubus_object_method_exists(const char *obj);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -674,7 +674,7 @@ static char *handle_reference_value(struct dmctx *ctx, struct json_object *linke
|
||||||
char *pref = NULL;
|
char *pref = NULL;
|
||||||
|
|
||||||
adm_entry_get_reference_param(ctx, linker_path, key_value, &pref);
|
adm_entry_get_reference_param(ctx, linker_path, key_value, &pref);
|
||||||
return pref;
|
return pref ? pref : dmstrdup("");
|
||||||
} else {
|
} else {
|
||||||
char buf_ref[256 + 32] = {0};
|
char buf_ref[256 + 32] = {0};
|
||||||
|
|
||||||
|
|
@ -2084,7 +2084,6 @@ static void create_parse_obj(DMOBJ *dm_entryobj, char *obj_path, json_object *jo
|
||||||
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
|
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
|
||||||
dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
|
dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
|
||||||
dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
|
dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
|
||||||
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) {
|
if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) {
|
||||||
|
|
@ -2114,7 +2113,6 @@ static void create_parse_param(DMOBJ *dm_entryobj, char *obj_path, char *param,
|
||||||
dm_entryobj->dynamicleaf = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
|
dm_entryobj->dynamicleaf = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
|
||||||
dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
|
dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
|
||||||
dm_entryobj->dynamicleaf[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
|
dm_entryobj->dynamicleaf[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
|
||||||
dm_entryobj->dynamicleaf[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf == NULL) {
|
if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ FILE(GLOB BBFDM_API_SOURCES *.c)
|
||||||
|
|
||||||
ADD_LIBRARY(bbfdm-api-v2 SHARED ${BBFDM_API_SOURCES})
|
ADD_LIBRARY(bbfdm-api-v2 SHARED ${BBFDM_API_SOURCES})
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(bbfdm-api-v2 uci ubus)
|
TARGET_LINK_LIBRARIES(bbfdm-api-v2 uci ubus ubox)
|
||||||
|
|
||||||
INSTALL(TARGETS bbfdm-api-v2
|
INSTALL(TARGETS bbfdm-api-v2
|
||||||
LIBRARY DESTINATION usr/lib)
|
LIBRARY DESTINATION usr/lib)
|
||||||
|
|
|
||||||
|
|
@ -92,3 +92,19 @@ int bbfdm_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, cons
|
||||||
ubus_complete_request_async(ubus_ctx, req);
|
ubus_complete_request_async(ubus_ctx, req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bbfdm_ubus_send_event(struct bbfdm_ctx *bbfdm_ctx, const char *obj, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
if (!bbfdm_ctx || !bbfdm_ctx->ubus_ctx) {
|
||||||
|
BBFDM_ERR("Invalid context or UBUS context is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = ubus_send_event(bbfdm_ctx->ubus_ctx, obj, msg);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
BBFDM_ERR("UBUS send event failed for obj='%s', error code=%d", obj, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,38 @@ int bbfdm_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, cons
|
||||||
bbfdm_free_ctx(&ctx); \
|
bbfdm_free_ctx(&ctx); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends an event to a UBUS object.
|
||||||
|
*
|
||||||
|
* This function sends an event to the specified UBUS object with the provided
|
||||||
|
* message data. The event is transmitted using the UBUS system.
|
||||||
|
*
|
||||||
|
* @param[in] bbfdm_ctx Pointer to the BBFDM context.
|
||||||
|
* @param[in] obj Name of the UBUS object to send the event to.
|
||||||
|
* @param[in] msg Pointer to a `blob_attr` message containing event data.
|
||||||
|
* @return 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
int bbfdm_ubus_send_event(struct bbfdm_ctx *bbfdm_ctx, const char *obj, struct blob_attr *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends an event to a UBUS object.
|
||||||
|
*
|
||||||
|
* This macro simplifies the process of initializing a context, sending an event,
|
||||||
|
* and cleaning up the context.
|
||||||
|
*
|
||||||
|
* @param obj The name of the UBUS object to send the event to.
|
||||||
|
* @param msg Pointer to a `blob_attr` message containing event data.
|
||||||
|
* @return Always returns 0.
|
||||||
|
*/
|
||||||
|
#define BBFDM_UBUS_SEND_EVENT(obj, msg) \
|
||||||
|
do { \
|
||||||
|
struct bbfdm_ctx ctx = {0}; \
|
||||||
|
memset(&ctx, 0, sizeof(struct bbfdm_ctx)); \
|
||||||
|
bbfdm_init_ctx(&ctx); \
|
||||||
|
bbfdm_ubus_send_event(&ctx, obj, msg); \
|
||||||
|
bbfdm_free_ctx(&ctx); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -13,25 +13,22 @@ struct bbfdm_async_req {
|
||||||
struct ubus_context *ctx;
|
struct ubus_context *ctx;
|
||||||
struct ubus_request_data req;
|
struct ubus_request_data req;
|
||||||
struct uloop_process process;
|
struct uloop_process process;
|
||||||
bool is_operate;
|
|
||||||
void *result;
|
void *result;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct bbfdm_config {
|
typedef struct bbfdm_config {
|
||||||
struct list_head list_objs; // Micro-service list of objects to expose
|
|
||||||
char service_name[32]; // Service name for micro-service identification
|
char service_name[32]; // Service name for micro-service identification
|
||||||
char in_type[32]; // Input type, Possible values: { 'JSON', 'DotSo' }
|
char in_name[128]; // Service plugin path
|
||||||
char in_name[128]; // plugin path
|
char in_plugin_dir[128]; // Service extra/internal plugin directory path
|
||||||
char in_plugin_dir[128]; // extra plugin directory path
|
|
||||||
char out_name[128]; // Ubus name to use
|
char out_name[128]; // Ubus name to use
|
||||||
char out_parent_dm[32]; // Parent device for micro-service
|
|
||||||
char out_root_obj[32]; // Ubus name to use as root data model
|
|
||||||
} bbfdm_config_t;
|
} bbfdm_config_t;
|
||||||
|
|
||||||
struct bbfdm_context {
|
struct bbfdm_context {
|
||||||
bbfdm_config_t config;
|
bbfdm_config_t config;
|
||||||
struct ubus_context ubus_ctx;
|
struct ubus_context ubus_ctx;
|
||||||
struct list_head event_handlers;
|
struct list_head event_handlers;
|
||||||
|
struct list_head linker_list;
|
||||||
|
struct list_head obj_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ev_handler_node {
|
struct ev_handler_node {
|
||||||
|
|
@ -47,8 +44,6 @@ typedef struct bbfdm_data {
|
||||||
struct list_head *plist;
|
struct list_head *plist;
|
||||||
struct dmctx bbf_ctx;
|
struct dmctx bbf_ctx;
|
||||||
struct blob_buf bb;
|
struct blob_buf bb;
|
||||||
uint8_t depth;
|
|
||||||
bool is_raw;
|
|
||||||
} bbfdm_data_t;
|
} bbfdm_data_t;
|
||||||
|
|
||||||
int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx);
|
int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx);
|
||||||
|
|
@ -58,6 +53,4 @@ void bbfdm_ubus_set_service_name(struct bbfdm_context *bbfdm_ctx, const char *sr
|
||||||
void bbfdm_ubus_set_log_level(int log_level);
|
void bbfdm_ubus_set_log_level(int log_level);
|
||||||
void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj);
|
void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj);
|
||||||
|
|
||||||
void bbfdm_schedule_instance_refresh_timer(struct ubus_context *ctx, int start_in_sec); // To be removed later
|
|
||||||
|
|
||||||
#endif /* BBFDM_UBUS_H */
|
#endif /* BBFDM_UBUS_H */
|
||||||
|
|
|
||||||
|
|
@ -12,64 +12,6 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "get_helper.h"
|
#include "get_helper.h"
|
||||||
|
|
||||||
bool get_boolean_string(char *value)
|
|
||||||
{
|
|
||||||
if (!value)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (strncasecmp(value, "true", 4) == 0 ||
|
|
||||||
value[0] == '1' ||
|
|
||||||
strncasecmp(value, "on", 2) == 0 ||
|
|
||||||
strncasecmp(value, "yes", 3) == 0 ||
|
|
||||||
strncasecmp(value, "enabled", 7) == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_node_instance(char *path)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
char *rb = NULL;
|
|
||||||
|
|
||||||
BBF_DEBUG("entry |%s|", path);
|
|
||||||
if (!path)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (path[0] == '[') {
|
|
||||||
char temp_char[MAX_DM_KEY_LEN] = {'\0'};
|
|
||||||
size_t shift;
|
|
||||||
|
|
||||||
rb = strchr(path, ']');
|
|
||||||
shift = (size_t) labs(rb - path);
|
|
||||||
strncpyt(temp_char, path, shift + 1);
|
|
||||||
if (!match(temp_char, GLOB_EXPR, 0, NULL))
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
if (strtol(path, NULL, 10))
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RE utilities
|
|
||||||
int count_delim(const char *path)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
char *token, *save;
|
|
||||||
char *pp = strdup(path);
|
|
||||||
|
|
||||||
token = strtok_r(pp, ".", &save);
|
|
||||||
while (token) {
|
|
||||||
token = strtok_r(NULL, ".", &save);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
free(pp);
|
|
||||||
|
|
||||||
// count is the count of tokens
|
|
||||||
return (count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool validate_msglen(bbfdm_data_t *data)
|
bool validate_msglen(bbfdm_data_t *data)
|
||||||
{
|
{
|
||||||
size_t data_len = blob_pad_len(data->bbf_ctx.bb.head);
|
size_t data_len = blob_pad_len(data->bbf_ctx.bb.head);
|
||||||
|
|
@ -85,39 +27,6 @@ bool validate_msglen(bbfdm_data_t *data)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_dm_type(char *dm_type)
|
|
||||||
{
|
|
||||||
if (dm_type == NULL)
|
|
||||||
return DMT_STRING;
|
|
||||||
|
|
||||||
if (DM_STRCMP(dm_type, DMT_TYPE[DMT_STRING]) == 0)
|
|
||||||
return DMT_STRING;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNINT]) == 0)
|
|
||||||
return DMT_UNINT;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_INT]) == 0)
|
|
||||||
return DMT_INT;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNLONG]) == 0)
|
|
||||||
return DMT_UNLONG;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_LONG]) == 0)
|
|
||||||
return DMT_LONG;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BOOL]) == 0)
|
|
||||||
return DMT_BOOL;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_TIME]) == 0)
|
|
||||||
return DMT_TIME;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_HEXBIN]) == 0)
|
|
||||||
return DMT_HEXBIN;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BASE64]) == 0)
|
|
||||||
return DMT_BASE64;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_COMMAND]) == 0)
|
|
||||||
return DMT_COMMAND;
|
|
||||||
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_EVENT]) == 0)
|
|
||||||
return DMT_EVENT;
|
|
||||||
else
|
|
||||||
return DMT_STRING;
|
|
||||||
|
|
||||||
return DMT_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
// glibc doesn't guarantee a 0 termianted string on strncpy
|
// glibc doesn't guarantee a 0 termianted string on strncpy
|
||||||
// strncpy with always 0 terminated string
|
// strncpy with always 0 terminated string
|
||||||
void strncpyt(char *dst, const char *src, size_t n)
|
void strncpyt(char *dst, const char *src, size_t n)
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,8 @@
|
||||||
#include <libbbfdm-api/legacy/dmcommon.h>
|
#include <libbbfdm-api/legacy/dmcommon.h>
|
||||||
#include "bbfdm-ubus.h"
|
#include "bbfdm-ubus.h"
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
|
||||||
#define TO_STR(x) STRINGIFY(x)
|
|
||||||
|
|
||||||
#define ROOT_NODE "Device."
|
|
||||||
#define BBF_EVENT_NAME "event"
|
|
||||||
|
|
||||||
#define MAX_DM_KEY_LEN 256
|
|
||||||
#define MAX_DM_PATH 1024
|
#define MAX_DM_PATH 1024
|
||||||
#define MAX_DM_VALUE 4096
|
#define MAX_DM_VALUE 4096
|
||||||
#define DM_VALUE_SEP ","
|
|
||||||
#define DELIM '.'
|
|
||||||
|
|
||||||
#ifdef BBFDM_MAX_MSG_LEN
|
#ifdef BBFDM_MAX_MSG_LEN
|
||||||
#define DEF_IPC_DATA_LEN (BBFDM_MAX_MSG_LEN - 128) // Configured Len - 128 bytes
|
#define DEF_IPC_DATA_LEN (BBFDM_MAX_MSG_LEN - 128) // Configured Len - 128 bytes
|
||||||
|
|
@ -35,21 +26,11 @@
|
||||||
#define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes
|
#define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GLOB_CHAR "[[+*]+"
|
|
||||||
#define GLOB_EXPR "[=><]+"
|
|
||||||
|
|
||||||
extern DMOBJ *DEAMON_DM_ROOT_OBJ;
|
extern DMOBJ *DEAMON_DM_ROOT_OBJ;
|
||||||
extern DM_MAP_OBJ *INTERNAL_ROOT_TREE;
|
extern DM_MAP_OBJ *INTERNAL_ROOT_TREE;
|
||||||
|
|
||||||
bool is_node_instance(char *path);
|
|
||||||
int count_delim(const char *path);
|
|
||||||
|
|
||||||
bool get_boolean_string(char *value);
|
|
||||||
bool validate_msglen(bbfdm_data_t *data);
|
bool validate_msglen(bbfdm_data_t *data);
|
||||||
|
|
||||||
int get_dm_type(char *dm_type);
|
|
||||||
|
|
||||||
int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath, struct list_head *resolved_paths);
|
|
||||||
void strncpyt(char *dst, const char *src, size_t n);
|
void strncpyt(char *dst, const char *src, size_t n);
|
||||||
|
|
||||||
#endif /* COMMON_H */
|
#endif /* COMMON_H */
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand
|
||||||
.iscommand = false,
|
.iscommand = false,
|
||||||
.isevent = true,
|
.isevent = true,
|
||||||
.isinfo = false,
|
.isinfo = false,
|
||||||
.disable_mservice_browse = true,
|
|
||||||
.dm_type = BBFDM_USP
|
.dm_type = BBFDM_USP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -107,7 +106,7 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand
|
||||||
if (!e_args)
|
if (!e_args)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
snprintf(e_args->method_name, sizeof(e_args->method_name), "%s.%s", DM_STRLEN(u->config.out_root_obj) ? u->config.out_root_obj : u->config.out_name, BBF_EVENT_NAME);
|
snprintf(e_args->method_name, sizeof(e_args->method_name), "%s.event", BBFDM_DEFAULT_UBUS_OBJ);
|
||||||
|
|
||||||
e_args->blob_data = (struct blob_attr *)calloc(1, blob_data_len);
|
e_args->blob_data = (struct blob_attr *)calloc(1, blob_data_len);
|
||||||
|
|
||||||
|
|
@ -155,7 +154,6 @@ int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list)
|
||||||
.iscommand = false,
|
.iscommand = false,
|
||||||
.isevent = true,
|
.isevent = true,
|
||||||
.isinfo = false,
|
.isinfo = false,
|
||||||
.disable_mservice_browse = true,
|
|
||||||
.dm_type = BBFDM_USP
|
.dm_type = BBFDM_USP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,34 +3,23 @@
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DM_GET_PATH,
|
DM_GET_PATH,
|
||||||
DM_GET_PATHS,
|
|
||||||
DM_GET_MAXDEPTH,
|
|
||||||
DM_GET_OPTIONAL,
|
DM_GET_OPTIONAL,
|
||||||
__DM_GET_MAX
|
__DM_GET_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DM_INSTANCES_PATH,
|
DM_INSTANCES_PATH,
|
||||||
DM_INSTANCES_PATHS,
|
|
||||||
DM_INSTANCES_FIRST_LEVEL,
|
|
||||||
DM_INSTANCES_OPTIONAL,
|
DM_INSTANCES_OPTIONAL,
|
||||||
__DM_INSTANCES_MAX
|
__DM_INSTANCES_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DM_SCHEMA_PATH,
|
DM_SCHEMA_PATH,
|
||||||
DM_SCHEMA_PATHS,
|
|
||||||
DM_SCHEMA_FIRST_LEVEL,
|
DM_SCHEMA_FIRST_LEVEL,
|
||||||
DM_SCHEMA_OPTIONAL,
|
DM_SCHEMA_OPTIONAL,
|
||||||
__DM_SCHEMA_MAX
|
__DM_SCHEMA_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
void bbfdm_get_value(bbfdm_data_t *data, void *output);
|
void bbfdm_get(bbfdm_data_t *data, int method);
|
||||||
|
|
||||||
void bbfdm_get_names(bbfdm_data_t *data);
|
|
||||||
|
|
||||||
void bbfdm_get_instances(bbfdm_data_t *data);
|
|
||||||
|
|
||||||
void bbfdm_get_supported_dm(bbfdm_data_t *data);
|
|
||||||
|
|
||||||
#endif /* GET_H */
|
#endif /* GET_H */
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include "get_helper.h"
|
#include "get_helper.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "pretty_print.h"
|
|
||||||
|
|
||||||
DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
|
DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
|
||||||
DM_MAP_OBJ *INTERNAL_ROOT_TREE = NULL;
|
DM_MAP_OBJ *INTERNAL_ROOT_TREE = NULL;
|
||||||
|
|
@ -60,12 +59,36 @@ void bbf_sub_cleanup(struct dmctx *dm_ctx)
|
||||||
bbf_ctx_clean_sub(dm_ctx);
|
bbf_ctx_clean_sub(dm_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool match_with_path_list(struct list_head *plist, char *entry)
|
||||||
|
{
|
||||||
|
struct pathNode *node;
|
||||||
|
|
||||||
|
list_for_each_entry(node, plist, list) {
|
||||||
|
if (strncmp(node->path, entry, strlen(node->path)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool present_in_path_list(struct list_head *plist, char *entry)
|
bool present_in_path_list(struct list_head *plist, char *entry)
|
||||||
{
|
{
|
||||||
struct pathNode *pos;
|
struct pathNode *node;
|
||||||
|
|
||||||
list_for_each_entry(pos, plist, list) {
|
list_for_each_entry(node, plist, list) {
|
||||||
if (!strcmp(pos->path, entry))
|
if (!strcmp(node->path, entry))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool present_in_pv_list(struct list_head *pv_list, char *entry)
|
||||||
|
{
|
||||||
|
struct pvNode *node = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(node, pv_list, list) {
|
||||||
|
if (!strcmp(node->param, entry))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +161,7 @@ void free_path_list(struct list_head *plist)
|
||||||
void fill_err_code_table(bbfdm_data_t *data, int fault)
|
void fill_err_code_table(bbfdm_data_t *data, int fault)
|
||||||
{
|
{
|
||||||
void *table = blobmsg_open_table(&data->bb, NULL);
|
void *table = blobmsg_open_table(&data->bb, NULL);
|
||||||
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param ? data->bbf_ctx.in_param : "");
|
bb_add_string(&data->bb, "path", data->bbf_ctx.in_param);
|
||||||
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
|
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
|
||||||
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
|
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
|
||||||
blobmsg_close_table(&data->bb, table);
|
blobmsg_close_table(&data->bb, table);
|
||||||
|
|
@ -148,104 +171,9 @@ void fill_err_code_array(bbfdm_data_t *data, int fault)
|
||||||
{
|
{
|
||||||
void *array = blobmsg_open_array(&data->bb, "results");
|
void *array = blobmsg_open_array(&data->bb, "results");
|
||||||
void *table = blobmsg_open_table(&data->bb, NULL);
|
void *table = blobmsg_open_table(&data->bb, NULL);
|
||||||
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param);
|
bb_add_string(&data->bb, "path", data->bbf_ctx.in_param);
|
||||||
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
|
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
|
||||||
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
|
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
|
||||||
blobmsg_close_table(&data->bb, table);
|
blobmsg_close_table(&data->bb, table);
|
||||||
blobmsg_close_array(&data->bb, array);
|
blobmsg_close_array(&data->bb, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CountConsecutiveDigits(char *p)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
int num_digits;
|
|
||||||
|
|
||||||
num_digits = 0;
|
|
||||||
c = *p++;
|
|
||||||
while ((c >= '0') && (c <= 9))
|
|
||||||
{
|
|
||||||
num_digits++;
|
|
||||||
c = *p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return num_digits;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_path(const void *arg1, const void *arg2)
|
|
||||||
{
|
|
||||||
const struct pvNode *pv1 = (const struct pvNode *)arg1;
|
|
||||||
const struct pvNode *pv2 = (const struct pvNode *)arg2;
|
|
||||||
|
|
||||||
char *s1 = pv1->param;
|
|
||||||
char *s2 = pv2->param;
|
|
||||||
|
|
||||||
char c1, c2;
|
|
||||||
int num_digits_s1;
|
|
||||||
int num_digits_s2;
|
|
||||||
int delta;
|
|
||||||
|
|
||||||
// Skip all characters which are the same
|
|
||||||
while (true) {
|
|
||||||
c1 = *s1;
|
|
||||||
c2 = *s2;
|
|
||||||
|
|
||||||
// Exit if reached the end of either string
|
|
||||||
if ((c1 == '\0') || (c2 == '\0')) {
|
|
||||||
// NOTE: The following comparision puts s1 before s2, if s1 terminates before s2 (and vice versa)
|
|
||||||
return (int)c1 - (int)c2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit if the characters do not match
|
|
||||||
if (c1 != c2) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As characters match, move to next characters
|
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the code gets here, then we have reached a character which is different
|
|
||||||
// Determine the number of digits in the rest of the string (this may be 0 if the first character is not a digit)
|
|
||||||
num_digits_s1 = CountConsecutiveDigits(s1);
|
|
||||||
num_digits_s2 = CountConsecutiveDigits(s2);
|
|
||||||
|
|
||||||
// Determine if the number of digits in s1 is greater than in s2 (if so, s1 comes after s2)
|
|
||||||
delta = num_digits_s1 - num_digits_s2;
|
|
||||||
if (delta != 0) {
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the code gets here, then the strings contain either no digits, or the same number of digits,
|
|
||||||
// so just compare the characters (this also works if the characters are digits)
|
|
||||||
return (int)c1 - (int)c2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a pointer to the sorted array of PVs, memory need to be freed by caller
|
|
||||||
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count)
|
|
||||||
{
|
|
||||||
if (!pv_list)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (list_empty(pv_list) || pv_count == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
struct pvNode *arr = (struct pvNode *)calloc(pv_count, sizeof(struct pvNode));
|
|
||||||
if (arr == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
struct pvNode *pv = NULL;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(pv, pv_list, list) {
|
|
||||||
if (i == pv_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
memcpy(&arr[i], pv, sizeof(struct pvNode));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort(arr, pv_count, sizeof(struct pvNode), compare_path);
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ void bbf_cleanup(struct dmctx *dm_ctx);
|
||||||
void bbf_sub_init(struct dmctx *dm_ctx);
|
void bbf_sub_init(struct dmctx *dm_ctx);
|
||||||
void bbf_sub_cleanup(struct dmctx *dm_ctx);
|
void bbf_sub_cleanup(struct dmctx *dm_ctx);
|
||||||
|
|
||||||
bool present_in_path_list(struct list_head *plist, char *entry);
|
bool present_in_pv_list(struct list_head *pv_list, char *entry);
|
||||||
|
|
||||||
void add_pv_list(const char *para, const char *val, const char *type, struct list_head *pv_list);
|
void add_pv_list(const char *para, const char *val, const char *type, struct list_head *pv_list);
|
||||||
void free_pv_list(struct list_head *pv_list);
|
void free_pv_list(struct list_head *pv_list);
|
||||||
|
|
||||||
|
bool match_with_path_list(struct list_head *plist, char *entry);
|
||||||
|
bool present_in_path_list(struct list_head *plist, char *entry);
|
||||||
void add_path_list(const char *param, struct list_head *plist);
|
void add_path_list(const char *param, struct list_head *plist);
|
||||||
void free_path_list(struct list_head *plist);
|
void free_path_list(struct list_head *plist);
|
||||||
|
|
||||||
|
|
@ -37,6 +38,4 @@ void fill_err_code_array(bbfdm_data_t *data, int fault);
|
||||||
|
|
||||||
void bb_add_string(struct blob_buf *bb, const char *name, const char *value);
|
void bb_add_string(struct blob_buf *bb, const char *name, const char *value);
|
||||||
|
|
||||||
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count);
|
|
||||||
|
|
||||||
#endif /* GET_HELPER_H */
|
#endif /* GET_HELPER_H */
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "operate.h"
|
|
||||||
#include "get_helper.h"
|
#include "get_helper.h"
|
||||||
#include "pretty_print.h"
|
|
||||||
|
|
||||||
#include <libubus.h>
|
#include <libubus.h>
|
||||||
|
|
||||||
|
|
@ -20,71 +18,31 @@ void bbfdm_operate_cmd(bbfdm_data_t *data, void *output)
|
||||||
{
|
{
|
||||||
int fault = 0;
|
int fault = 0;
|
||||||
|
|
||||||
memset(&data->bb, 0, sizeof(struct blob_buf));
|
|
||||||
|
|
||||||
bbf_init(&data->bbf_ctx);
|
bbf_init(&data->bbf_ctx);
|
||||||
blob_buf_init(&data->bb, 0);
|
|
||||||
|
|
||||||
void *global_array = blobmsg_open_array(&data->bb, "results");
|
void *array = blobmsg_open_array(&data->bbf_ctx.bb, "results");
|
||||||
|
|
||||||
void *global_table = blobmsg_open_table(&data->bb, NULL);
|
void *table = blobmsg_open_table(&data->bbf_ctx.bb, NULL);
|
||||||
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param);
|
bb_add_string(&data->bbf_ctx.bb, "path", data->bbf_ctx.in_param);
|
||||||
blobmsg_add_string(&data->bb, "data", data->bbf_ctx.linker);
|
bb_add_string(&data->bbf_ctx.bb, "data", data->bbf_ctx.linker);
|
||||||
|
void *output_array = blobmsg_open_array(&data->bbf_ctx.bb, "output");
|
||||||
|
|
||||||
fault = bbfdm_cmd_exec(&data->bbf_ctx, BBF_OPERATE);
|
fault = bbfdm_cmd_exec(&data->bbf_ctx, BBF_OPERATE);
|
||||||
if (fault == 0) {
|
if (fault) {
|
||||||
void *table = NULL, *array = NULL;
|
blobmsg_add_u32(&data->bbf_ctx.bb, "fault", fault);
|
||||||
struct blob_attr *cur = NULL;
|
bb_add_string(&data->bbf_ctx.bb, "fault_msg", data->bbf_ctx.fault_msg);
|
||||||
size_t rem = 0;
|
|
||||||
|
|
||||||
if (data->is_raw) {
|
|
||||||
array = blobmsg_open_array(&data->bb, "output");
|
|
||||||
blobmsg_for_each_attr(cur, data->bbf_ctx.bb.head, rem) {
|
|
||||||
blobmsg_add_blob(&data->bb, cur);
|
|
||||||
}
|
|
||||||
blobmsg_close_array(&data->bb, array);
|
|
||||||
} else {
|
|
||||||
LIST_HEAD(pv_local);
|
|
||||||
|
|
||||||
blobmsg_for_each_attr(cur, data->bbf_ctx.bb.head, rem) {
|
|
||||||
struct blob_attr *tb[3] = {0};
|
|
||||||
const struct blobmsg_policy p[3] = {
|
|
||||||
{ "path", BLOBMSG_TYPE_STRING },
|
|
||||||
{ "data", BLOBMSG_TYPE_STRING },
|
|
||||||
{ "type", BLOBMSG_TYPE_STRING }
|
|
||||||
};
|
|
||||||
|
|
||||||
blobmsg_parse(p, 3, tb, blobmsg_data(cur), blobmsg_len(cur));
|
|
||||||
|
|
||||||
char *op_name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
|
|
||||||
char *op_data = (tb[1]) ? blobmsg_get_string(tb[1]) : "";
|
|
||||||
char *op_type = (tb[2]) ? blobmsg_get_string(tb[2]) : "";
|
|
||||||
|
|
||||||
add_pv_list(op_name, op_data, op_type, &pv_local);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
array = blobmsg_open_array(&data->bb, "output");
|
blobmsg_close_array(&data->bbf_ctx.bb, output_array);
|
||||||
table = blobmsg_open_table(&data->bb, NULL);
|
blobmsg_close_table(&data->bbf_ctx.bb, table);
|
||||||
prepare_result_blob(&data->bb, &pv_local);
|
|
||||||
blobmsg_close_table(&data->bb, table);
|
|
||||||
blobmsg_close_array(&data->bb, array);
|
|
||||||
|
|
||||||
free_pv_list(&pv_local);
|
blobmsg_close_array(&data->bbf_ctx.bb, array);
|
||||||
}
|
|
||||||
} else {
|
if (output) {
|
||||||
blobmsg_add_u32(&data->bb, "fault", fault);
|
memcpy(output, data->bbf_ctx.bb.head, blob_pad_len(data->bbf_ctx.bb.head));
|
||||||
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
|
} else if (data->ctx && data->req) {
|
||||||
|
ubus_send_reply(data->ctx, data->req, data->bbf_ctx.bb.head);
|
||||||
}
|
}
|
||||||
|
|
||||||
blobmsg_close_table(&data->bb, global_table);
|
|
||||||
|
|
||||||
blobmsg_close_array(&data->bb, global_array);
|
|
||||||
|
|
||||||
if (output)
|
|
||||||
memcpy(output, data->bb.head, blob_pad_len(data->bb.head));
|
|
||||||
else
|
|
||||||
ubus_send_reply(data->ctx, data->req, data->bb.head);
|
|
||||||
|
|
||||||
blob_buf_free(&data->bb);
|
|
||||||
bbf_cleanup(&data->bbf_ctx);
|
bbf_cleanup(&data->bbf_ctx);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* plugin.c: Plugin file bbfdmd
|
* plugin.c: Plugin file bbfdmd
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
|
* Copyright (C) 2023-2025 IOPSYS Software Solutions AB. All rights reserved.
|
||||||
*
|
*
|
||||||
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
|
||||||
*
|
*
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "libbbfdm-api/legacy/plugin/json_plugin.h"
|
#include "libbbfdm-api/legacy/plugin/json_plugin.h"
|
||||||
|
|
||||||
|
|
||||||
extern struct list_head loaded_json_files;
|
extern struct list_head loaded_json_files;
|
||||||
extern struct list_head json_list;
|
extern struct list_head json_list;
|
||||||
extern struct list_head json_memhead;
|
extern struct list_head json_memhead;
|
||||||
|
|
@ -37,34 +36,9 @@ static uint8_t find_number_of_objects(DM_MAP_OBJ *dynamic_obj)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_dotso_micro_service_out_args(bbfdm_config_t *config, DMOBJ *entryobj, char *parent_dm)
|
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dynamic_obj, DMOBJ **main_entry)
|
||||||
{
|
{
|
||||||
char ms_name[128] = {0};
|
if (!dynamic_obj || !main_entry) {
|
||||||
|
|
||||||
if (!config || !entryobj || !parent_dm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
strncpyt(config->out_parent_dm, parent_dm, sizeof(config->out_parent_dm));
|
|
||||||
|
|
||||||
for (; (entryobj && entryobj->obj); entryobj++) {
|
|
||||||
|
|
||||||
add_path_list(entryobj->obj, &config->list_objs);
|
|
||||||
|
|
||||||
int len = DM_STRLEN(ms_name);
|
|
||||||
if (len == 0) {
|
|
||||||
snprintf(ms_name, sizeof(ms_name), "%s.%s", config->out_root_obj, entryobj->obj);
|
|
||||||
} else {
|
|
||||||
snprintf(ms_name + len, sizeof(ms_name) - len, "_%s", entryobj->obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DM_STRLEN(config->out_name) == 0)
|
|
||||||
strncpyt(config->out_name, ms_name, sizeof(config->out_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dynamic_obj, bbfdm_config_t *config, DMOBJ **main_entry)
|
|
||||||
{
|
|
||||||
if (!dynamic_obj || !config || !main_entry) {
|
|
||||||
BBF_ERR("Input validation failed");
|
BBF_ERR("Input validation failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -92,9 +66,14 @@ int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dyna
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out arguments if it is running as micro-service
|
if (dynamic_obj[i].root_obj != NULL && bbfdm_ctx != NULL) {
|
||||||
if (dm_is_micro_service() == true)
|
struct dm_obj_s *entryobj = dynamic_obj[i].root_obj;
|
||||||
fill_dotso_micro_service_out_args(config, dynamic_obj[i].root_obj, node_obj);
|
for (; (entryobj && entryobj->obj); entryobj++) {
|
||||||
|
char path[MAX_DM_PATH] = {0};
|
||||||
|
snprintf(path, sizeof(path), "%s%s.", node_obj, entryobj->obj);
|
||||||
|
add_path_list(path, &bbfdm_ctx->obj_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node_obj[len-1] = 0;
|
node_obj[len-1] = 0;
|
||||||
|
|
||||||
|
|
@ -112,9 +91,9 @@ int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dyna
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry)
|
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, DMOBJ **main_entry)
|
||||||
{
|
{
|
||||||
if (!lib_handle || !file_path || !strlen(file_path) || !config || !main_entry) {
|
if (!lib_handle || !file_path || !strlen(file_path) || !main_entry) {
|
||||||
BBF_ERR("Input validation failed");
|
BBF_ERR("Input validation failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +111,7 @@ int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle,
|
||||||
//Dynamic Object
|
//Dynamic Object
|
||||||
*(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj");
|
*(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj");
|
||||||
|
|
||||||
return bbfdm_load_internal_plugin(bbfdm_ctx, dynamic_obj, config, main_entry);
|
return bbfdm_load_internal_plugin(bbfdm_ctx, dynamic_obj, main_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle)
|
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle)
|
||||||
|
|
@ -159,28 +138,11 @@ int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_json_micro_service_out_args(bbfdm_config_t *config, char *parent_dm, char *obj, char *ms_name, size_t ms_name_len)
|
static int bbfdm_load_json_plugin(struct bbfdm_context *bbfdm_ctx, struct list_head *json_plugin, struct list_head *json_list,
|
||||||
{
|
struct list_head *json_memhead, const char *file_path, DMOBJ **main_entry)
|
||||||
if (!config || !obj)
|
|
||||||
return;
|
|
||||||
|
|
||||||
strncpyt(config->out_parent_dm, parent_dm, sizeof(config->out_parent_dm));
|
|
||||||
add_path_list(obj, &config->list_objs);
|
|
||||||
|
|
||||||
int len = DM_STRLEN(ms_name);
|
|
||||||
if (len == 0) {
|
|
||||||
snprintf(ms_name, ms_name_len, "%s.%s", config->out_root_obj, obj);
|
|
||||||
} else {
|
|
||||||
snprintf(ms_name + len, ms_name_len - len, "_%s", obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead,
|
|
||||||
const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry)
|
|
||||||
{
|
{
|
||||||
DMOBJ *dm_entryobj = NULL;
|
DMOBJ *dm_entryobj = NULL;
|
||||||
int json_plugin_version = JSON_VERSION_0;
|
int json_plugin_version = JSON_VERSION_0;
|
||||||
char ms_name[128] = {0};
|
|
||||||
uint8_t idx = 0;
|
uint8_t idx = 0;
|
||||||
|
|
||||||
if (!file_path || !strlen(file_path) || !main_entry) {
|
if (!file_path || !strlen(file_path) || !main_entry) {
|
||||||
|
|
@ -218,7 +180,7 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char obj_prefix[1024] = {0};
|
char obj_prefix[512] = {0};
|
||||||
json_plugin_find_prefix_obj(node_obj, obj_prefix, sizeof(obj_prefix));
|
json_plugin_find_prefix_obj(node_obj, obj_prefix, sizeof(obj_prefix));
|
||||||
|
|
||||||
int obj_prefix_len = strlen(obj_prefix);
|
int obj_prefix_len = strlen(obj_prefix);
|
||||||
|
|
@ -234,9 +196,9 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out arguments if it is running as micro-service
|
char path[MAX_DM_PATH] = {0};
|
||||||
if (dm_is_micro_service() == true)
|
snprintf(path, sizeof(path), "%s%s.", obj_prefix, obj_name);
|
||||||
fill_json_micro_service_out_args(config, obj_prefix, obj_name, ms_name, sizeof(ms_name));
|
add_path_list(path, &bbfdm_ctx->obj_list);
|
||||||
|
|
||||||
// Remove '.' from object prefix
|
// Remove '.' from object prefix
|
||||||
if (obj_prefix[obj_prefix_len - 1] == '.')
|
if (obj_prefix[obj_prefix_len - 1] == '.')
|
||||||
|
|
@ -264,9 +226,6 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DM_STRLEN(config->out_name) == 0)
|
|
||||||
strncpyt(config->out_name, ms_name, sizeof(config->out_name));
|
|
||||||
|
|
||||||
*main_entry = dm_entryobj;
|
*main_entry = dm_entryobj;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -276,7 +235,7 @@ int bbfdm_free_json_plugin(void)
|
||||||
return free_json_plugins();
|
return free_json_plugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, bbfdm_config_t *config, DMOBJ **main_entry)
|
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, DMOBJ **main_entry)
|
||||||
{
|
{
|
||||||
char file_path[128] = {0};
|
char file_path[128] = {0};
|
||||||
int err = -1;
|
int err = -1;
|
||||||
|
|
@ -293,10 +252,10 @@ int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handl
|
||||||
BBF_ERR("Input file without extension");
|
BBF_ERR("Input file without extension");
|
||||||
} else if (strcasecmp(ext, ".json") == 0) {
|
} else if (strcasecmp(ext, ".json") == 0) {
|
||||||
BBF_INFO("Loading JSON plugin %s", file_path);
|
BBF_INFO("Loading JSON plugin %s", file_path);
|
||||||
err = bbfdm_load_json_plugin(&loaded_json_files, &json_list, &json_memhead, file_path, config, main_entry);
|
err = bbfdm_load_json_plugin(bbfdm_ctx, &loaded_json_files, &json_list, &json_memhead, file_path, main_entry);
|
||||||
} else if (strcasecmp(ext, ".so") == 0) {
|
} else if (strcasecmp(ext, ".so") == 0) {
|
||||||
BBF_INFO("Loading DotSo plugin %s", file_path);
|
BBF_INFO("Loading DotSo plugin %s", file_path);
|
||||||
err = bbfdm_load_dotso_plugin(bbfdm_ctx, lib_handle, file_path, config, main_entry);
|
err = bbfdm_load_dotso_plugin(bbfdm_ctx, lib_handle, file_path, main_entry);
|
||||||
} else {
|
} else {
|
||||||
BBF_ERR("Input type %s not supported", ext);
|
BBF_ERR("Input type %s not supported", ext);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,12 @@
|
||||||
|
|
||||||
#ifndef PLUGIN_H
|
#ifndef PLUGIN_H
|
||||||
|
|
||||||
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *Dynamic_Obj, bbfdm_config_t *config, DMOBJ **main_entry);
|
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *Dynamic_Obj, DMOBJ **main_entry);
|
||||||
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, bbfdm_config_t *config, DMOBJ **main_entry);
|
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, DMOBJ **main_entry);
|
||||||
|
|
||||||
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry);
|
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, DMOBJ **main_entry);
|
||||||
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void *lib_handle);
|
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void *lib_handle);
|
||||||
|
|
||||||
int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead,
|
|
||||||
const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry);
|
|
||||||
int bbfdm_free_json_plugin(void);
|
int bbfdm_free_json_plugin(void);
|
||||||
|
|
||||||
#endif /* PLUGIN_H */
|
#endif /* PLUGIN_H */
|
||||||
|
|
|
||||||
|
|
@ -1,444 +0,0 @@
|
||||||
/*
|
|
||||||
* pretty_print.c: utils for pretty printing of results
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved.
|
|
||||||
*
|
|
||||||
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
|
|
||||||
*
|
|
||||||
* See LICENSE file for license related information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "get_helper.h"
|
|
||||||
#include "pretty_print.h"
|
|
||||||
|
|
||||||
// private function and structures
|
|
||||||
struct resultstack {
|
|
||||||
void *cookie;
|
|
||||||
char *key;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool is_search_by_reference(char *path)
|
|
||||||
{
|
|
||||||
BBF_DEBUG("Entry |%s|", path);
|
|
||||||
if (match(path, "[+]+", 0, NULL)) {
|
|
||||||
size_t pindex = 0, bindex = 0;
|
|
||||||
char *last_plus, *last_bracket;
|
|
||||||
|
|
||||||
last_bracket = strrchr(path, ']');
|
|
||||||
if (!last_bracket)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
last_plus = strrchr(path, '+');
|
|
||||||
|
|
||||||
pindex = (size_t)labs(last_plus - path);
|
|
||||||
bindex = (size_t)labs(last_bracket - path);
|
|
||||||
|
|
||||||
if (pindex > bindex)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if matched start will have first match index, end will have end index
|
|
||||||
static bool is_res_required(char *str, size_t *start, size_t *len)
|
|
||||||
{
|
|
||||||
|
|
||||||
BBF_DEBUG("Entry |%s|", str);
|
|
||||||
if (match(str, GLOB_CHAR, 0, NULL)) {
|
|
||||||
size_t s_len = 0, b_len = 0, p_len = 0;
|
|
||||||
char *star, *b_start, *b_end, *plus;
|
|
||||||
char temp_char[MAX_DM_KEY_LEN] = {'\0'};
|
|
||||||
|
|
||||||
s_len = DM_STRLEN(str);
|
|
||||||
b_len = s_len;
|
|
||||||
p_len = s_len;
|
|
||||||
|
|
||||||
star = strchr(str, '*');
|
|
||||||
b_start = strchr(str, '[');
|
|
||||||
b_end = strchr(str, ']');
|
|
||||||
plus = strchr(str, '+');
|
|
||||||
|
|
||||||
if (star)
|
|
||||||
s_len = (size_t)labs(star - str);
|
|
||||||
|
|
||||||
if (b_start)
|
|
||||||
b_len = (size_t)labs(b_start - str);
|
|
||||||
|
|
||||||
if (plus)
|
|
||||||
p_len = (size_t)labs(plus - str);
|
|
||||||
|
|
||||||
*start = MIN(MIN(s_len, p_len), b_len);
|
|
||||||
if (*start == s_len) {
|
|
||||||
*len = 1;
|
|
||||||
} else if (*start == p_len) {
|
|
||||||
size_t i = 0, index = 0;
|
|
||||||
|
|
||||||
while ((str+i) != plus) {
|
|
||||||
if (str[i] == DELIM)
|
|
||||||
index = i;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
*start = index+1;
|
|
||||||
*len = p_len - index;
|
|
||||||
} else {
|
|
||||||
*len = (size_t)labs(b_end - b_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if naming with aliases used
|
|
||||||
snprintf(temp_char, *len+1, "%s", str + *start);
|
|
||||||
if (match(temp_char, GLOB_EXPR, 0, NULL))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (match(temp_char, "[*+]+", 0, NULL))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*start = DM_STRLEN(str);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_glob_len(char *path)
|
|
||||||
{
|
|
||||||
size_t m_index = 0, m_len = 0, ret = 0;
|
|
||||||
size_t plen = DM_STRLEN(path);
|
|
||||||
char temp_name[MAX_DM_KEY_LEN] = {'\0'};
|
|
||||||
char *end = NULL;
|
|
||||||
|
|
||||||
BBF_DEBUG("Entry");
|
|
||||||
if (is_res_required(path, &m_index, &m_len)) {
|
|
||||||
if (m_index <= MAX_DM_KEY_LEN)
|
|
||||||
snprintf(temp_name, m_index, "%s", path);
|
|
||||||
end = strrchr(temp_name, DELIM);
|
|
||||||
if (end != NULL)
|
|
||||||
ret = m_index - DM_STRLEN(end);
|
|
||||||
} else {
|
|
||||||
char name[MAX_DM_KEY_LEN] = {'\0'};
|
|
||||||
|
|
||||||
if (plen == 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (path[plen - 1] == DELIM) {
|
|
||||||
if (plen <= MAX_DM_KEY_LEN)
|
|
||||||
snprintf(name, plen, "%s", path);
|
|
||||||
} else {
|
|
||||||
ret = 1;
|
|
||||||
if (plen < MAX_DM_KEY_LEN)
|
|
||||||
snprintf(name, plen + 1, "%s", path);
|
|
||||||
}
|
|
||||||
end = strrchr(name, DELIM);
|
|
||||||
if (end == NULL)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = ret + DM_STRLEN(path) - DM_STRLEN(end);
|
|
||||||
if (is_node_instance(end+1)) {
|
|
||||||
int copy_len = plen - DM_STRLEN(end);
|
|
||||||
if (copy_len <= MAX_DM_KEY_LEN)
|
|
||||||
snprintf(temp_name, copy_len, "%s", path);
|
|
||||||
|
|
||||||
end = strrchr(temp_name, DELIM);
|
|
||||||
if (end != NULL)
|
|
||||||
ret = ret - DM_STRLEN(end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resulting(uint8_t maxdepth, char *path, struct dmctx *bbf_ctx, struct list_head *pv_local)
|
|
||||||
{
|
|
||||||
struct blob_attr *cur = NULL;
|
|
||||||
size_t rem = 0;
|
|
||||||
uint8_t count;
|
|
||||||
|
|
||||||
size_t plen = get_glob_len(bbf_ctx->in_param);
|
|
||||||
size_t path_len = DM_STRLEN(path);
|
|
||||||
if (path_len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
blobmsg_for_each_attr(cur, bbf_ctx->bb.head, rem) {
|
|
||||||
struct blob_attr *tb[3] = {0};
|
|
||||||
const struct blobmsg_policy p[3] = {
|
|
||||||
{ "path", BLOBMSG_TYPE_STRING },
|
|
||||||
{ "data", BLOBMSG_TYPE_STRING },
|
|
||||||
{ "type", BLOBMSG_TYPE_STRING }
|
|
||||||
};
|
|
||||||
|
|
||||||
blobmsg_parse(p, 3, tb, blobmsg_data(cur), blobmsg_len(cur));
|
|
||||||
|
|
||||||
char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
|
|
||||||
char *data = (tb[1]) ? blobmsg_get_string(tb[1]) : "";
|
|
||||||
char *type = (tb[2]) ? blobmsg_get_string(tb[2]) : "";
|
|
||||||
|
|
||||||
if (match(name, path, 0, NULL)) {
|
|
||||||
if (is_search_by_reference(bbf_ctx->in_param))
|
|
||||||
plen = 0;
|
|
||||||
|
|
||||||
if (maxdepth > 4 || maxdepth == 0) {
|
|
||||||
add_pv_list(name + plen, data, type, pv_local);
|
|
||||||
} else {
|
|
||||||
count = count_delim(name + path_len);
|
|
||||||
if (count < maxdepth)
|
|
||||||
add_pv_list(name + plen, data, type, pv_local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_data_blob(struct blob_buf *bb, char *param, char *value, char *type)
|
|
||||||
{
|
|
||||||
if (param == NULL || value == NULL || type == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BBF_DEBUG("# Adding BLOB (%s)::(%s)", param, value);
|
|
||||||
switch (get_dm_type(type)) {
|
|
||||||
case DMT_UNINT:
|
|
||||||
blobmsg_add_u64(bb, param, (uint32_t)strtoul(value, NULL, 10));
|
|
||||||
break;
|
|
||||||
case DMT_INT:
|
|
||||||
blobmsg_add_u32(bb, param, (int)strtol(value, NULL, 10));
|
|
||||||
break;
|
|
||||||
case DMT_LONG:
|
|
||||||
blobmsg_add_u64(bb, param, strtoll(value, NULL, 10));
|
|
||||||
break;
|
|
||||||
case DMT_UNLONG:
|
|
||||||
blobmsg_add_u64(bb, param, (uint64_t)strtoull(value, NULL, 10));
|
|
||||||
break;
|
|
||||||
case DMT_BOOL:
|
|
||||||
if (get_boolean_string(value))
|
|
||||||
blobmsg_add_u8(bb, param, true);
|
|
||||||
else
|
|
||||||
blobmsg_add_u8(bb, param, false);
|
|
||||||
break;
|
|
||||||
default: //"xsd:hexbin" "xsd:dateTime" "xsd:string"
|
|
||||||
bb_add_string(bb, param, value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_result_list(struct list_head *head)
|
|
||||||
{
|
|
||||||
struct resultstack *iter = NULL, *node = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(iter, node, head, list) {
|
|
||||||
free(iter->key);
|
|
||||||
list_del(&iter->list);
|
|
||||||
free(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_result_node(struct resultstack *rnode)
|
|
||||||
{
|
|
||||||
if (rnode) {
|
|
||||||
BBF_DEBUG("## ResStack DEL(%s)", rnode->key);
|
|
||||||
free(rnode->key);
|
|
||||||
list_del(&rnode->list);
|
|
||||||
free(rnode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_result_node(struct list_head *rlist, char *key, char *cookie)
|
|
||||||
{
|
|
||||||
struct resultstack *rnode = NULL;
|
|
||||||
|
|
||||||
rnode = (struct resultstack *)calloc(1, sizeof(*rnode));
|
|
||||||
if (!rnode) {
|
|
||||||
BBF_ERR("Out of memory!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&rnode->list);
|
|
||||||
list_add(&rnode->list, rlist);
|
|
||||||
|
|
||||||
rnode->key = (key) ? strdup(key) : strdup("");
|
|
||||||
rnode->cookie = cookie;
|
|
||||||
BBF_DEBUG("## ResSTACK ADD (%s) ##", rnode->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_leaf_element(char *path)
|
|
||||||
{
|
|
||||||
char *ptr = NULL;
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ptr = strchr(path, DELIM);
|
|
||||||
|
|
||||||
return (ptr == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool get_next_element(char *path, char *param)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
len = DM_STRLEN(path);
|
|
||||||
ptr = strchr(path, DELIM);
|
|
||||||
if (ptr)
|
|
||||||
strncpyt(param, path, (size_t)labs(ptr - path) + 1);
|
|
||||||
else
|
|
||||||
strncpyt(param, path, len + 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_same_group(char *path, char *group)
|
|
||||||
{
|
|
||||||
return (strncmp(path, group, DM_STRLEN(group)) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool add_paths_to_stack(struct blob_buf *bb, char *path, size_t begin,
|
|
||||||
struct pvNode *pv, struct list_head *result_stack)
|
|
||||||
{
|
|
||||||
char key[MAX_DM_KEY_LEN], param[MAX_DM_PATH], *ptr;
|
|
||||||
size_t parsed_len = 0;
|
|
||||||
void *c;
|
|
||||||
char *k;
|
|
||||||
|
|
||||||
ptr = path + begin;
|
|
||||||
if (is_leaf_element(ptr)) {
|
|
||||||
add_data_blob(bb, ptr, pv->val, pv->type);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (get_next_element(ptr, key)) {
|
|
||||||
parsed_len += DM_STRLEN(key) + 1;
|
|
||||||
ptr += DM_STRLEN(key) + 1;
|
|
||||||
if (is_leaf_element(ptr)) {
|
|
||||||
strncpyt(param, path, begin + parsed_len + 1);
|
|
||||||
if (is_node_instance(key))
|
|
||||||
c = blobmsg_open_table(bb, NULL);
|
|
||||||
else
|
|
||||||
c = blobmsg_open_table(bb, key);
|
|
||||||
|
|
||||||
k = param;
|
|
||||||
add_result_node(result_stack, k, c);
|
|
||||||
add_data_blob(bb, ptr, pv->val, pv->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
strncpyt(param, pv->param, begin + parsed_len + 1);
|
|
||||||
if (is_node_instance(ptr))
|
|
||||||
c = blobmsg_open_array(bb, key);
|
|
||||||
else
|
|
||||||
c = blobmsg_open_table(bb, key);
|
|
||||||
|
|
||||||
k = param;
|
|
||||||
add_result_node(result_stack, k, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public functions
|
|
||||||
void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
size_t len;
|
|
||||||
struct pvNode *pv;
|
|
||||||
struct resultstack *rnode;
|
|
||||||
|
|
||||||
LIST_HEAD(result_stack);
|
|
||||||
|
|
||||||
if (!bb || !pv_list)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (list_empty(pv_list))
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
list_for_each_entry(pv, pv_list, list) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pvNode *sortedPV = sort_pv_path(pv_list, count);
|
|
||||||
if (sortedPV == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
pv = &sortedPV[i];
|
|
||||||
ptr = pv->param;
|
|
||||||
if (list_empty(&result_stack)) {
|
|
||||||
BBF_DEBUG("stack empty Processing (%s)", ptr);
|
|
||||||
add_paths_to_stack(bb, pv->param, 0, pv, &result_stack);
|
|
||||||
} else {
|
|
||||||
bool is_done = false;
|
|
||||||
|
|
||||||
while (is_done == false) {
|
|
||||||
rnode = list_entry(result_stack.next, struct resultstack, list);
|
|
||||||
if (is_same_group(ptr, rnode->key)) {
|
|
||||||
len = DM_STRLEN(rnode->key);
|
|
||||||
ptr = ptr + len;
|
|
||||||
|
|
||||||
BBF_DEBUG("GROUP (%s), ptr(%s), len(%zu)", pv->param, ptr, len);
|
|
||||||
add_paths_to_stack(bb, pv->param, len, pv, &result_stack);
|
|
||||||
is_done = true;
|
|
||||||
} else {
|
|
||||||
// Get the latest entry before deleting it
|
|
||||||
BBF_DEBUG("DIFF GROUP pv(%s), param(%s)", pv->param, ptr);
|
|
||||||
blobmsg_close_table(bb, rnode->cookie);
|
|
||||||
free_result_node(rnode);
|
|
||||||
if (list_empty(&result_stack)) {
|
|
||||||
add_paths_to_stack(bb, pv->param, 0, pv, &result_stack);
|
|
||||||
is_done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(sortedPV);
|
|
||||||
|
|
||||||
// Close the stack entry if left
|
|
||||||
list_for_each_entry(rnode, &result_stack, list) {
|
|
||||||
blobmsg_close_table(bb, rnode->cookie);
|
|
||||||
}
|
|
||||||
free_result_list(&result_stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void prepare_raw_result(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd)
|
|
||||||
{
|
|
||||||
struct pathNode *iter = NULL;
|
|
||||||
struct blob_attr *cur = NULL;
|
|
||||||
size_t rem = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(iter, rslvd, list) {
|
|
||||||
if (DM_STRLEN(iter->path) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
blobmsg_for_each_attr(cur, bbf_ctx->bb.head, rem) {
|
|
||||||
struct blob_attr *tb[1] = {0};
|
|
||||||
const struct blobmsg_policy p[1] = {
|
|
||||||
{ "path", BLOBMSG_TYPE_STRING }
|
|
||||||
};
|
|
||||||
|
|
||||||
blobmsg_parse(p, 1, tb, blobmsg_data(cur), blobmsg_len(cur));
|
|
||||||
|
|
||||||
char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
|
|
||||||
|
|
||||||
if (match(name, iter->path, 0, NULL)) {
|
|
||||||
blobmsg_add_blob(bb, cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void prepare_pretty_result(uint8_t maxdepth, struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd)
|
|
||||||
{
|
|
||||||
struct pathNode *iter = NULL;
|
|
||||||
|
|
||||||
LIST_HEAD(pv_local);
|
|
||||||
|
|
||||||
BBF_DEBUG("################### DATA to PROCESS ##################");
|
|
||||||
list_for_each_entry(iter, rslvd, list) {
|
|
||||||
BBF_DEBUG("## %s ##", iter->path);
|
|
||||||
resulting(maxdepth, iter->path, bbf_ctx, &pv_local);
|
|
||||||
}
|
|
||||||
BBF_DEBUG("######################################################");
|
|
||||||
|
|
||||||
prepare_result_blob(bb, &pv_local);
|
|
||||||
|
|
||||||
free_pv_list(&pv_local);
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* pretty_print.h: utils for pretty printing of results
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved.
|
|
||||||
*
|
|
||||||
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
|
|
||||||
*
|
|
||||||
* See LICENSE file for license related information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PRETTY_PRINT_H
|
|
||||||
#define PRETTY_PRINT_H
|
|
||||||
|
|
||||||
void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list);
|
|
||||||
void prepare_raw_result(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd);
|
|
||||||
void prepare_pretty_result(uint8_t maxdepth, struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd);
|
|
||||||
|
|
||||||
#endif /* PRETTY_PRINT_H */
|
|
||||||
|
|
@ -17,10 +17,9 @@
|
||||||
int bbfdm_set_value(bbfdm_data_t *data)
|
int bbfdm_set_value(bbfdm_data_t *data)
|
||||||
{
|
{
|
||||||
struct pvNode *pv = NULL;
|
struct pvNode *pv = NULL;
|
||||||
void *array = NULL;
|
|
||||||
int fault = 0;
|
int fault = 0;
|
||||||
|
|
||||||
array = blobmsg_open_array(&data->bb, "results");
|
void *array = blobmsg_open_array(&data->bb, "results");
|
||||||
|
|
||||||
list_for_each_entry(pv, data->plist, list) {
|
list_for_each_entry(pv, data->plist, list) {
|
||||||
data->bbf_ctx.in_param = pv->param;
|
data->bbf_ctx.in_param = pv->param;
|
||||||
|
|
@ -43,39 +42,8 @@ int bbfdm_set_value(bbfdm_data_t *data)
|
||||||
return fault;
|
return fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_resolved_paths(bbfdm_data_t *data, char *path, char *value, char *type, struct list_head *pv_list)
|
int fill_pvlist_set(char *param_name, char *param_value, char *data_type, struct blob_attr *blob_table, struct list_head *pv_list)
|
||||||
{
|
{
|
||||||
int fault = 0;
|
|
||||||
|
|
||||||
if (!path || !value || !pv_list)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
LIST_HEAD(resolved_paths);
|
|
||||||
bbf_sub_init(&data->bbf_ctx);
|
|
||||||
|
|
||||||
fault = get_resolved_paths(&data->bbf_ctx, path, &resolved_paths);
|
|
||||||
|
|
||||||
if (!fault) {
|
|
||||||
struct pathNode *p;
|
|
||||||
|
|
||||||
list_for_each_entry(p, &resolved_paths, list) {
|
|
||||||
add_pv_list(p->path, value, type, pv_list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bbf_sub_cleanup(&data->bbf_ctx);
|
|
||||||
free_path_list(&resolved_paths);
|
|
||||||
|
|
||||||
return fault;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, char *type, struct blob_attr *blob_table, struct list_head *pv_list)
|
|
||||||
{
|
|
||||||
struct blob_attr *attr;
|
|
||||||
struct blobmsg_hdr *hdr;
|
|
||||||
char path[MAX_DM_PATH], value[MAX_DM_VALUE];
|
|
||||||
int fault = 0;
|
|
||||||
|
|
||||||
size_t plen = DM_STRLEN(param_name);
|
size_t plen = DM_STRLEN(param_name);
|
||||||
if (plen == 0)
|
if (plen == 0)
|
||||||
return USP_FAULT_INVALID_PATH;
|
return USP_FAULT_INVALID_PATH;
|
||||||
|
|
@ -86,18 +54,21 @@ int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, cha
|
||||||
if (param_name[plen - 1] == '.')
|
if (param_name[plen - 1] == '.')
|
||||||
return USP_FAULT_INVALID_PATH;
|
return USP_FAULT_INVALID_PATH;
|
||||||
|
|
||||||
fault = set_resolved_paths(data, param_name, param_value, type, pv_list);
|
add_pv_list(param_name, param_value, data_type, pv_list);
|
||||||
if (fault)
|
return 0;
|
||||||
return fault;
|
|
||||||
|
|
||||||
blob__table:
|
blob__table:
|
||||||
|
|
||||||
if (!blob_table)
|
if (!blob_table)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
struct blob_attr *attr;
|
||||||
|
struct blobmsg_hdr *hdr;
|
||||||
|
|
||||||
size_t tlen = (size_t)blobmsg_data_len(blob_table);
|
size_t tlen = (size_t)blobmsg_data_len(blob_table);
|
||||||
|
|
||||||
__blob_for_each_attr(attr, blobmsg_data(blob_table), tlen) {
|
__blob_for_each_attr(attr, blobmsg_data(blob_table), tlen) {
|
||||||
|
char path[MAX_DM_PATH] = {0}, value[MAX_DM_VALUE] = {0};
|
||||||
hdr = blob_data(attr);
|
hdr = blob_data(attr);
|
||||||
|
|
||||||
switch (blob_id(attr)) {
|
switch (blob_id(attr)) {
|
||||||
|
|
@ -122,9 +93,7 @@ blob__table:
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(path, MAX_DM_PATH, "%s%s", param_name, (char *)hdr->name);
|
snprintf(path, MAX_DM_PATH, "%s%s", param_name, (char *)hdr->name);
|
||||||
fault = set_resolved_paths(data, path, value, NULL, pv_list);
|
add_pv_list(path, value, NULL, pv_list);
|
||||||
if (fault)
|
|
||||||
return fault;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ enum {
|
||||||
__DM_SET_MAX,
|
__DM_SET_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, char *type, struct blob_attr *blob_table, struct list_head *pv_list);
|
int fill_pvlist_set(char *param_name, char *param_value, char *data_type, struct blob_attr *blob_table, struct list_head *pv_list);
|
||||||
int bbfdm_set_value(bbfdm_data_t *data);
|
int bbfdm_set_value(bbfdm_data_t *data);
|
||||||
|
|
||||||
#endif /* SET_H */
|
#endif /* SET_H */
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ ADD_DEFINITIONS(-Wall -Werror -g3 -D_GNU_SOURCE -DBBF_VENDOR_PREFIX="${BBF_VENDO
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2")
|
||||||
FILE(GLOB BBF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
|
FILE(GLOB BBF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
|
||||||
|
|
||||||
ADD_LIBRARY(bbfdm STATIC ${BBF_SOURCES})
|
ADD_LIBRARY(core SHARED ${BBF_SOURCES})
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(bbfdm uci ubus ubox json-c blobmsg_json m bbfdm-api ssl crypto)
|
TARGET_LINK_LIBRARIES(core uci ubus ubox json-c blobmsg_json m bbfdm-api ssl crypto)
|
||||||
|
|
||||||
INSTALL(TARGETS bbfdm
|
INSTALL(TARGETS core
|
||||||
LIBRARY DESTINATION usr/lib
|
LIBRARY DESTINATION usr/lib
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -19,7 +19,6 @@ INSTALL(DIRECTORY DESTINATION etc/bbfdm)
|
||||||
INSTALL(DIRECTORY DESTINATION etc/bbfdm/dmmap)
|
INSTALL(DIRECTORY DESTINATION etc/bbfdm/dmmap)
|
||||||
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm)
|
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm)
|
||||||
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/scripts)
|
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/scripts)
|
||||||
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/plugins)
|
|
||||||
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/micro_services)
|
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/micro_services)
|
||||||
INSTALL(DIRECTORY DESTINATION usr/libexec/rpcd)
|
INSTALL(DIRECTORY DESTINATION usr/libexec/rpcd)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,11 @@ DM_MAP_OBJ tDynamicObj[] = {
|
||||||
|
|
||||||
/* *** Device. *** */
|
/* *** Device. *** */
|
||||||
DMOBJ tDMRootObj[] = {
|
DMOBJ tDMRootObj[] = {
|
||||||
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
|
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
|
||||||
{"LANConfigSecurity", &DMREAD, NULL, NULL, "file:/etc/config/users", NULL, NULL, NULL, NULL, tLANConfigSecurityParams, NULL, BBFDM_BOTH, NULL},
|
{"LANConfigSecurity", &DMREAD, NULL, NULL, "file:/etc/config/users", NULL, NULL, NULL, NULL, tLANConfigSecurityParams, NULL, BBFDM_BOTH},
|
||||||
{"Schedules", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSchedulesObj, tSchedulesParams, NULL, BBFDM_BOTH, NULL},
|
{"Schedules", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSchedulesObj, tSchedulesParams, NULL, BBFDM_BOTH},
|
||||||
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSecurityObj, tSecurityParams, NULL, BBFDM_BOTH, NULL},
|
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSecurityObj, tSecurityParams, NULL, BBFDM_CWMP},
|
||||||
{"Services", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, BBFDM_BOTH, NULL},
|
{"GatewayInfo", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGatewayInfoParams, NULL, BBFDM_CWMP},
|
||||||
{"GatewayInfo", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGatewayInfoParams, NULL, BBFDM_CWMP, NULL},
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -299,20 +299,20 @@ static int get_SecurityCertificate_SignatureAlgorithm(char *refparam, struct dmc
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
/* *** Device.Security. *** */
|
/* *** Device.Security. *** */
|
||||||
DMOBJ tSecurityObj[] = {
|
DMOBJ tSecurityObj[] = {
|
||||||
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
|
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
|
||||||
{"Certificate", &DMREAD, NULL, NULL, NULL, browseSecurityCertificateInst, NULL, NULL, NULL, tSecurityCertificateParams, NULL, BBFDM_CWMP, NULL},
|
{"Certificate", &DMREAD, NULL, NULL, NULL, browseSecurityCertificateInst, NULL, NULL, NULL, tSecurityCertificateParams, NULL, BBFDM_CWMP},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
DMLEAF tSecurityParams[] = {
|
DMLEAF tSecurityParams[] = {
|
||||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
|
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
|
||||||
{"CertificateNumberOfEntries", &DMREAD, DMT_UNINT, get_Security_CertificateNumberOfEntries, NULL, BBFDM_CWMP},
|
{"CertificateNumberOfEntries", &DMREAD, DMT_UNINT, get_Security_CertificateNumberOfEntries, NULL, BBFDM_CWMP},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* *** Device.Security.Certificate.{i}. *** */
|
/* *** Device.Security.Certificate.{i}. *** */
|
||||||
DMLEAF tSecurityCertificateParams[] = {
|
DMLEAF tSecurityCertificateParams[] = {
|
||||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
|
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
|
||||||
//{"Enable", &DMWRITE, DMT_BOOL, get_SecurityCertificate_Enable, set_SecurityCertificate_Enable, BBFDM_CWMP},
|
//{"Enable", &DMWRITE, DMT_BOOL, get_SecurityCertificate_Enable, set_SecurityCertificate_Enable, BBFDM_CWMP},
|
||||||
{"LastModif", &DMREAD, DMT_TIME, get_SecurityCertificate_LastModif, NULL, BBFDM_CWMP},
|
{"LastModif", &DMREAD, DMT_TIME, get_SecurityCertificate_LastModif, NULL, BBFDM_CWMP},
|
||||||
{"SerialNumber", &DMREAD, DMT_STRING, get_SecurityCertificate_SerialNumber, NULL, BBFDM_CWMP, DM_FLAG_UNIQUE},
|
{"SerialNumber", &DMREAD, DMT_STRING, get_SecurityCertificate_SerialNumber, NULL, BBFDM_CWMP, DM_FLAG_UNIQUE},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -g -Wall
|
CFLAGS = -g -Wall
|
||||||
LDFLAGS = -lcmocka -lbbfdm-api -lbbfdm -lubox -lblobmsg_json -ljson-c -lssl -lcrypto --coverage
|
LDFLAGS = -lcmocka -lbbfdm-api -lcore -lubox -lblobmsg_json -ljson-c -lssl -lcrypto --coverage
|
||||||
UNIT_TESTS = unit_test_bbfd
|
UNIT_TESTS = unit_test_bbfd
|
||||||
FUNCTIONAL_TESTS = functional_test_bbfd
|
FUNCTIONAL_TESTS = functional_test_bbfd
|
||||||
FUNCTIONAL_API_TESTS = functional_api_test_bbfd
|
FUNCTIONAL_API_TESTS = functional_api_test_bbfd
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ static int setup_teardown(void **state)
|
||||||
{
|
{
|
||||||
dm_init_mem(&bbf_ctx);
|
dm_init_mem(&bbf_ctx);
|
||||||
dm_uci_init(&bbf_ctx);
|
dm_uci_init(&bbf_ctx);
|
||||||
|
dm_ubus_init(&bbf_ctx);
|
||||||
bbf_ctx.dm_type = BBFDM_USP;
|
bbf_ctx.dm_type = BBFDM_USP;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +21,7 @@ static int group_teardown(void **state)
|
||||||
{
|
{
|
||||||
dm_uci_exit(&bbf_ctx);
|
dm_uci_exit(&bbf_ctx);
|
||||||
dm_clean_mem(&bbf_ctx);
|
dm_clean_mem(&bbf_ctx);
|
||||||
dmubus_free();
|
dm_ubus_free(&bbf_ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ static int teardown_commit(void **state)
|
||||||
|
|
||||||
static int group_init(void **state)
|
static int group_init(void **state)
|
||||||
{
|
{
|
||||||
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/plugins");
|
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ static int teardown_revert(void **state)
|
||||||
|
|
||||||
static int group_init(void **state)
|
static int group_init(void **state)
|
||||||
{
|
{
|
||||||
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/plugins");
|
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
41
test/files/etc/bbfdm/services/core.json
Normal file
41
test/files/etc/bbfdm/services/core.json
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"daemon": {
|
||||||
|
"enable": "1",
|
||||||
|
"service_name": "core",
|
||||||
|
"unified_daemon": false,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "LANConfigSecurity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "Schedules"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "Security",
|
||||||
|
"proto": "cwmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "GatewayInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "RootDataModelVersion"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "Reboot()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "FactoryReset()"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"loglevel": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,14 @@
|
||||||
{
|
{
|
||||||
"parent_dm": "Device.",
|
"parent_dm": "Device.",
|
||||||
"object": "RouterAdvertisement"
|
"object": "RouterAdvertisement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "IPv6rd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parent_dm": "Device.",
|
||||||
|
"object": "InterfaceStack"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
|
|
|
||||||
2
test/files/var/reset_reason
Normal file
2
test/files/var/reset_reason
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
reset reason: REBOOT
|
||||||
|
reset triggered: upgrade
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"args": {
|
"args": {
|
||||||
"path": "Device.DeviceInfo.Manufacturer",
|
"path": "Device.DeviceInfo.Manufacturer",
|
||||||
"optional": {"format":"raw", "proto":"usp"}
|
"optional": {"proto":"usp"}
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"args": {
|
"args": {
|
||||||
"path": "Device.DeviceInfo.Manufacturer",
|
"path": "Device.DeviceInfo.Manufacturer",
|
||||||
"optional": {"format":"raw", "proto":"cwmp"}
|
"optional": {"proto":"cwmp"}
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"args": {
|
"args": {
|
||||||
"path":"Device.WiFi.SSID.*.Alias",
|
"path":"Device.WiFi.SSID.*.Alias",
|
||||||
"optional": {"format":"raw", "proto":"cwmp"}
|
"optional": {"proto":"cwmp"}
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"args": {
|
"args": {
|
||||||
"path": "Device.DeviceInfo.Manufacturer",
|
"path": "Device.DeviceInfo.Manufacturer",
|
||||||
"optional": {"format":"raw", "proto":"both"}
|
"optional": {"proto":"both"}
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
|
|
@ -40,15 +40,6 @@
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"method": "get",
|
|
||||||
"args": {
|
|
||||||
"path": "Device.DeviceInfo.Manufacturer",
|
|
||||||
"optional": {"format":"raw", "proto":"usp"},
|
|
||||||
"maxdepth": "1"
|
|
||||||
},
|
|
||||||
"rc": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"args": {
|
"args": {
|
||||||
|
|
@ -78,7 +69,7 @@
|
||||||
"method": "instances",
|
"method": "instances",
|
||||||
"args": {
|
"args": {
|
||||||
"path": "Device.WiFi.SSID.",
|
"path": "Device.WiFi.SSID.",
|
||||||
"optional": {"format":"raw", "proto":"usp"}
|
"optional": {"proto":"usp"}
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
|
|
@ -104,14 +95,6 @@
|
||||||
},
|
},
|
||||||
"rc": 0
|
"rc": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"method": "get",
|
|
||||||
"args": {
|
|
||||||
"paths": ["Device.WiFi.SSID.1.SSID","Device.WiFi.SSID.2.SSID"],
|
|
||||||
"proto": "usp"
|
|
||||||
},
|
|
||||||
"rc": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"method": "set",
|
"method": "set",
|
||||||
"args": {
|
"args": {
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
|
|
||||||
TEST_NAME = "BUG_3536"
|
|
||||||
|
|
||||||
print("Running: " + TEST_NAME)
|
|
||||||
|
|
||||||
def bbf_get(path, proto = ""):
|
|
||||||
path_arg = "{\"path\":\"" + path + "\", \"optional\":{\"format\":\"raw\", \"proto\":\"" + proto + "\"}}"
|
|
||||||
cmd = ['ubus', 'call', 'bbfdm', 'get', path_arg]
|
|
||||||
|
|
||||||
out = subprocess.Popen(cmd,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
stdout,stderr = out.communicate()
|
|
||||||
return stdout
|
|
||||||
|
|
||||||
# check fault code of invalid path
|
|
||||||
output = json.loads(bbf_get("Device", "usp"))
|
|
||||||
assert output["results"][0]["fault"] == 7026, "Wrong fault code"
|
|
||||||
|
|
||||||
# check fault code of invalid path
|
|
||||||
output = json.loads(bbf_get("Device", "cwmp"))
|
|
||||||
assert output["results"][0]["fault"] == 9005, "Wrong fault code for cwmp"
|
|
||||||
|
|
||||||
# check fault code of invalid path
|
|
||||||
output = json.loads(bbf_get("Device"))
|
|
||||||
assert output["results"][0]["fault"] == 9005, "Wrong fault code for default proto"
|
|
||||||
|
|
||||||
print("PASS: " + TEST_NAME)
|
|
||||||
|
|
@ -15,12 +15,11 @@ if sock.exists():
|
||||||
else:
|
else:
|
||||||
assert ubus.connect()
|
assert ubus.connect()
|
||||||
|
|
||||||
out = ubus.call('bbfdm', 'get', {"path":"Device.", "optional":{"format":"raw"}})
|
|
||||||
assert isinstance(out[0]["results"][0], dict), "FAIL: get Device. on bbf with raw format"
|
|
||||||
|
|
||||||
# Check get operation for Device. path succeed
|
|
||||||
out = ubus.call('bbfdm', 'get', {"path":"Device."})
|
out = ubus.call('bbfdm', 'get', {"path":"Device."})
|
||||||
assert isinstance(out[0]['Device'], dict), "FAIL: get Device. on bbf with pretty format"
|
assert isinstance(out[0]["results"][0], dict), "FAIL: get Device."
|
||||||
|
|
||||||
|
out = ubus.call('bbfdm', 'get', {"path":"Device"})
|
||||||
|
assert out[0]["results"][0]["fault"] == 9005, "FAIL: get Device"
|
||||||
|
|
||||||
ubus.disconnect()
|
ubus.disconnect()
|
||||||
print("PASS: " + TEST_NAME)
|
print("PASS: " + TEST_NAME)
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import ubus
|
|
||||||
import json
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
TEST_NAME = "Validate ubus event bbf"
|
|
||||||
|
|
||||||
print("Running: " + TEST_NAME)
|
|
||||||
|
|
||||||
def callback(event, data):
|
|
||||||
print("PASS: " + TEST_NAME)
|
|
||||||
ubus.disconnect()
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
sock = pathlib.Path('/var/run/ubus/ubus.sock')
|
|
||||||
if sock.exists ():
|
|
||||||
assert ubus.connect('/var/run/ubus/ubus.sock')
|
|
||||||
else:
|
|
||||||
assert ubus.connect()
|
|
||||||
|
|
||||||
ubus.listen(("bbfdm.event", callback))
|
|
||||||
|
|
||||||
ubus.call("bbfdm", "notify_event", {"name":"Device.LocalAgent.TransferComplete!", "input":[{"path":"Command","data":"Backup()","type":"xsd:string"},{"path":"CommandKey","data":"","type":"xsd:string"}]})
|
|
||||||
|
|
||||||
ubus.loop()
|
|
||||||
|
|
||||||
ubus.disconnect()
|
|
||||||
|
|
||||||
print("FAIL: " + TEST_NAME)
|
|
||||||
|
|
@ -54,7 +54,6 @@ int main(int argc, char **argv)
|
||||||
DMOBJ *CLI_DM_ROOT_OBJ = NULL;
|
DMOBJ *CLI_DM_ROOT_OBJ = NULL;
|
||||||
void *cli_lib_handle = NULL;
|
void *cli_lib_handle = NULL;
|
||||||
struct dmctx bbfdm_ctx = {0};
|
struct dmctx bbfdm_ctx = {0};
|
||||||
bbfdm_config_t bbfdm_config = {0};
|
|
||||||
char *plugin_path = NULL, *plugin_dir = NULL, *dm_path = NULL;
|
char *plugin_path = NULL, *plugin_dir = NULL, *dm_path = NULL;
|
||||||
unsigned int proto = BBFDM_BOTH;
|
unsigned int proto = BBFDM_BOTH;
|
||||||
int err = 0, ch;
|
int err = 0, ch;
|
||||||
|
|
@ -83,9 +82,9 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin_path == NULL) {
|
if (plugin_path == NULL) {
|
||||||
err = bbfdm_load_internal_plugin(NULL, tDynamicObj, &bbfdm_config, &CLI_DM_ROOT_OBJ);
|
err = bbfdm_load_internal_plugin(NULL, tDynamicObj, &CLI_DM_ROOT_OBJ);
|
||||||
} else {
|
} else {
|
||||||
err = bbfdm_load_dotso_plugin(NULL, &cli_lib_handle, plugin_path, &bbfdm_config, &CLI_DM_ROOT_OBJ);
|
err = bbfdm_load_dotso_plugin(NULL, &cli_lib_handle, plugin_path, &CLI_DM_ROOT_OBJ);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err || !CLI_DM_ROOT_OBJ) {
|
if (err || !CLI_DM_ROOT_OBJ) {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ $(LIB): $(LIB_OBJS)
|
||||||
$(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
|
$(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp -f $(LIB) /usr/share/bbfdm/plugins/
|
cp -f $(LIB) /usr/share/bbfdm/micro_services/core/
|
||||||
cp -f *.json /usr/share/bbfdm/plugins
|
cp -f *.json /usr/share/bbfdm/micro_services/core/
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fv *.o $(LIB)
|
rm -fv *.o $(LIB)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import glob
|
||||||
# Constants
|
# Constants
|
||||||
BBF_ERROR_CODE = 0
|
BBF_ERROR_CODE = 0
|
||||||
CURRENT_PATH = os.getcwd()
|
CURRENT_PATH = os.getcwd()
|
||||||
BBF_PLUGIN_DIR = "/usr/share/bbfdm/plugins/"
|
BBF_MS_CORE_DIR = "/usr/share/bbfdm/micro_services/core/"
|
||||||
BBF_MS_DIR = "/usr/share/bbfdm/micro_services/"
|
BBF_MS_DIR = "/usr/share/bbfdm/micro_services/"
|
||||||
|
|
||||||
DM_JSON_FILE = os.path.join(CURRENT_PATH, "tools", "datamodel.json")
|
DM_JSON_FILE = os.path.join(CURRENT_PATH, "tools", "datamodel.json")
|
||||||
|
|
@ -151,7 +151,7 @@ def generate_shared_library(dm_name, source_files, vendor_prefix,
|
||||||
if is_microservice:
|
if is_microservice:
|
||||||
outdir = BBF_MS_DIR
|
outdir = BBF_MS_DIR
|
||||||
else:
|
else:
|
||||||
outdir = BBF_PLUGIN_DIR
|
outdir = BBF_MS_CORE_DIR
|
||||||
|
|
||||||
output_library = outdir + dm_name
|
output_library = outdir + dm_name
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ def build_and_install_dmcli():
|
||||||
"-lbbfdm-ubus",
|
"-lbbfdm-ubus",
|
||||||
"-lubox",
|
"-lubox",
|
||||||
"-lblobmsg_json",
|
"-lblobmsg_json",
|
||||||
"-lbbfdm",
|
"-lcore",
|
||||||
"-ljson-c",
|
"-ljson-c",
|
||||||
"-lssl",
|
"-lssl",
|
||||||
"-lcrypto",
|
"-lcrypto",
|
||||||
|
|
@ -257,7 +257,7 @@ def fill_list_dm(proto, dm_list, dm_name=None):
|
||||||
if dm_name:
|
if dm_name:
|
||||||
command = f"dm-cli -l {dm_name}"
|
command = f"dm-cli -l {dm_name}"
|
||||||
else:
|
else:
|
||||||
command = "dm-cli -p /usr/share/bbfdm/plugins"
|
command = "dm-cli -p /usr/share/bbfdm/micro_services/core"
|
||||||
|
|
||||||
# Add the appropriate flag (-c or -u) based on the proto value
|
# Add the appropriate flag (-c or -u) based on the proto value
|
||||||
if proto == "cwmp":
|
if proto == "cwmp":
|
||||||
|
|
@ -411,7 +411,7 @@ def download_and_build_plugins(plugins, vendor_prefix):
|
||||||
if filename.endswith('.c'):
|
if filename.endswith('.c'):
|
||||||
LIST_FILES.append(filename)
|
LIST_FILES.append(filename)
|
||||||
elif filename.endswith('.json'):
|
elif filename.endswith('.json'):
|
||||||
install_json_plugin(filename, "/usr/share/bbfdm/plugins/"+f"{plugin_index}_{name}.json", prefix)
|
install_json_plugin(filename, "/usr/share/bbfdm/micro_services/core/"+f"{plugin_index}_{name}.json", prefix)
|
||||||
else:
|
else:
|
||||||
BBF_ERROR_CODE += 1
|
BBF_ERROR_CODE += 1
|
||||||
print(f"# Unknown file format {filename} {BBF_ERROR_CODE}")
|
print(f"# Unknown file format {filename} {BBF_ERROR_CODE}")
|
||||||
|
|
|
||||||
|
|
@ -358,20 +358,13 @@
|
||||||
"proto": "git",
|
"proto": "git",
|
||||||
"version": "devel",
|
"version": "devel",
|
||||||
"dm_files": [
|
"dm_files": [
|
||||||
"src/wifi.c"
|
"src/wifi.c",
|
||||||
|
"src/dataelements.c"
|
||||||
],
|
],
|
||||||
"extra_dependencies": [
|
"extra_dependencies": [
|
||||||
"-lm"
|
"-lm"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"repo": "https://dev.iopsys.eu/bbf/wifidmd.git",
|
|
||||||
"proto": "git",
|
|
||||||
"version": "devel",
|
|
||||||
"dm_files": [
|
|
||||||
"src/dataelements.c"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"repo": "https://dev.iopsys.eu/hal/mcastmngr.git",
|
"repo": "https://dev.iopsys.eu/hal/mcastmngr.git",
|
||||||
"proto": "git",
|
"proto": "git",
|
||||||
|
|
@ -410,14 +403,6 @@
|
||||||
"test/obuspa_core_dm.json"
|
"test/obuspa_core_dm.json"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"repo": "https://dev.iopsys.eu/network/netmngr.git",
|
|
||||||
"proto": "git",
|
|
||||||
"version": "devel",
|
|
||||||
"dm_files": [
|
|
||||||
"src/interfacestack.c"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"repo": "https://dev.iopsys.eu/network/netmngr.git",
|
"repo": "https://dev.iopsys.eu/network/netmngr.git",
|
||||||
"proto": "git",
|
"proto": "git",
|
||||||
|
|
@ -438,7 +423,8 @@
|
||||||
"src/routeradvertisement.c",
|
"src/routeradvertisement.c",
|
||||||
"src/routing.c",
|
"src/routing.c",
|
||||||
"src/ipv6rd.c",
|
"src/ipv6rd.c",
|
||||||
"src/common.c"
|
"src/common.c",
|
||||||
|
"src/interfacestack.c"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue