diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4a02d340f92e549043c0a25b1893c8900f0a0a58..f26486f84123007bb026e9a5ed9fc9ccdfbf49cf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,14 @@ -include: - - project: 'iopsys/gitlab-ci-pipeline' - file: '/static-code-analysis.yml' - variables: DEBUG: 'TRUE' SOURCE_FOLDER: "." + FLAWFINDER_OPTIONS: "-m 4 --error-level=5" + CPD_OPTIONS: "--minimum-tokens 200 --language c --exclude ./daemon/json_rpc/ --files" CPPCHECK_OPTIONS: " --enable=performance,portability,information --inline-suppr" +include: + - project: 'iopsys/gitlab-ci-pipeline' + file: '/static-code-analysis.yml' + ref: '0.31' + stages: - static_code_analysis diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 498a99244c4747a69559ae76c41e463c7fe05ec3..8cdc38e616694703858f3db82c01a6d5dd1c9b97 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.0) PROJECT(tr104daemon C) OPTION(DM_ENABLE_UBUS "Build with UBus Support" OFF) +OPTION(DM_ENABLE_JSON_RPC "Build with JSON-RPC Support" OFF) IF(DM_ENABLE_UBUS) add_subdirectory(ubus) -ENDIF(DM_ENABLE_UBUS) +ELSEIF(DM_ENABLE_JSON_RPC) + add_subdirectory(json_rpc) +ENDIF() diff --git a/daemon/json_rpc/CMakeLists.txt b/daemon/json_rpc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce21d5b07f41c6a67c5ef39ea0d5ba4139757770 --- /dev/null +++ b/daemon/json_rpc/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0) + +PROJECT(tr104d) + +ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -fPIC -D_GNU_SOURCE) +ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}") + +OPTION(DM_ENABLE_DECT "Enable DECT support" OFF) + +IF(DM_ENABLE_DECT) + ADD_DEFINITIONS(-DDM_ENABLE_DECT) +ENDIF(DM_ENABLE_DECT) + +FILE(GLOB BBF_SOURCES *.c) +ADD_EXECUTABLE(tr104d ${BBF_SOURCES}) +TARGET_LINK_LIBRARIES(tr104d dmtree dm ubus ubox blobmsg_json uci json-c json_hal_server dl rt) + +INSTALL(TARGETS tr104d DESTINATION usr/sbin) diff --git a/daemon/json_rpc/add_delete.c b/daemon/json_rpc/add_delete.c new file mode 100644 index 0000000000000000000000000000000000000000..e0e465f1061d9625fc1f40027a728d1731053c41 --- /dev/null +++ b/daemon/json_rpc/add_delete.c @@ -0,0 +1,109 @@ +/* + * add_delete.c: Add/Delete handler for bbfdmd + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include "common.h" +#include "add_delete.h" +#include "get_helper.h" +#include "service_helper.h" + +int bbfdm_add_object(struct dmctx *bbf_ctx) +{ + char cur_ch; + int ret = 0; + struct dmctx bbf_ctx_inst, bbf_ctx_add_obj; + char *str = bbf_ctx->in_param, *multi_obj_str = NULL; + + INFO("Req to add object |%s|", bbf_ctx->in_param); + memset(&bbf_ctx_inst, 0, sizeof(bbf_ctx_inst)); + bbf_sub_init(&bbf_ctx_inst); + bbf_ctx_inst.in_param = bbf_ctx->in_param; + memset(&bbf_ctx_add_obj, 0, sizeof(bbf_ctx_add_obj)); + bbf_sub_init(&bbf_ctx_add_obj); + bbf_ctx_add_obj.in_param = bbf_ctx->in_param; + + while (!ret && (str = DM_STRCHR(str, '.'))) + { + cur_ch = str[1]; + str[1] = '\0'; + ret = bbfdm_cmd_exec(&bbf_ctx_inst, BBF_INSTANCES); + + if (ret && multi_obj_str) { + int ch = multi_obj_str[1]; + + multi_obj_str[1] = '\0'; + if ((ret = bbfdm_cmd_exec(&bbf_ctx_add_obj, BBF_ADD_OBJECT))) { + ERR("addObject: failed adding object (%s)", bbf_ctx_add_obj.in_param); + } + multi_obj_str[1] = ch; + } + + str[1] = cur_ch; + if ( cur_ch >= '1' && cur_ch <= '9') + multi_obj_str = str; + else + multi_obj_str = NULL; + str++; + } + bbf_sub_cleanup(&bbf_ctx_inst); + bbf_sub_cleanup(&bbf_ctx_add_obj); + + return ret; +} + +int del_object(char *obj_path) +{ + struct dmctx bbf_ctx; + int ret = 0; + + memset(&bbf_ctx, 0, sizeof(bbf_ctx)); + bbf_init(&bbf_ctx); + bbf_ctx.in_param = obj_path; + + INFO("Req to del object |%s|", obj_path); + if ((ret = bbfdm_cmd_exec(&bbf_ctx, BBF_DEL_OBJECT))) + ERR("Failed deleting (%s)", obj_path); + + bbf_cleanup(&bbf_ctx); + + return ret; +} + +int bbfdm_del_object(const json_object *jmsg, int param_count, json_object *jreply) +{ + int i; + hal_param_t param_request; + + if (jmsg == NULL || jreply == NULL) { + ERR("getParameters cb: invalid memory"); + return RETURN_ERR; + } + + for (i = 0; i < param_count; i++) { + /* Unpack the JSON and populate the data into request_param object */ + if (json_hal_get_param((json_object *)jmsg, i, GET_REQUEST_MESSAGE, + ¶m_request) != RETURN_OK) { + ERR("deleteObject cb: failed getting parameter"); + return RETURN_ERR; + } + + del_object(param_request.name); + if (json_hal_add_param(jreply, GET_RESPONSE_MESSAGE, ¶m_request) + != RETURN_OK) { + ERR("deleteObject cb: failed adding response"); + return RETURN_ERR; + } + } + + restart_services(); + + return RETURN_OK; +} + + diff --git a/daemon/json_rpc/add_delete.h b/daemon/json_rpc/add_delete.h new file mode 100644 index 0000000000000000000000000000000000000000..6329c3d54c803dbc71472066d491413d20f87605 --- /dev/null +++ b/daemon/json_rpc/add_delete.h @@ -0,0 +1,10 @@ +#ifndef ADD_DELETE_H +#define ADD_DELETE_H + +#include "common.h" +#include <json_hal_server.h> + +int bbfdm_add_object(struct dmctx *bbf_ctx); +int bbfdm_del_object(const json_object *jmsg, int param_count, json_object *jreply); + +#endif /* ADD_DELETE_H */ diff --git a/daemon/json_rpc/cli.c b/daemon/json_rpc/cli.c new file mode 100644 index 0000000000000000000000000000000000000000..7b392cb80a1be423c9351cd998c123ea613bd629 --- /dev/null +++ b/daemon/json_rpc/cli.c @@ -0,0 +1,381 @@ +/* + * cli.c: Cli command for bbfdmd + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "common.h" +#include "libdmtree/dmapi.h" +#include "libdmtree/dmjson.h" +#include "libdmtree/dmentry.h" + +#define UNUSED __attribute__((unused)) + +extern DMOBJ *DEAMON_DM_ROOT_OBJ; +extern DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2]; +extern DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE; + +extern int bbfdm_load_deamon_config(void); + +typedef struct { + struct dmctx bbf_ctx; + unsigned int instance_mode; + unsigned int proto; + char in_name[128]; + char in_type[8]; + char out_type[8]; + char *cmd; +} cli_data_t; + +typedef struct { + char *name; + int num_args; + int (*exec_cmd)(cli_data_t *cli_data, char *argv[]); + char *usage; +} cli_cmd_t; + +static int cli_exec_help(cli_data_t *cli_data UNUSED, char *argv[] UNUSED); +static int cli_exec_get(cli_data_t *cli_data, char *argv[]); +static int cli_exec_set(cli_data_t *cli_data, char *argv[]); +static int cli_exec_add(cli_data_t *cli_data, char *argv[]); +static int cli_exec_del(cli_data_t *cli_data, char *argv[]); +static int cli_exec_instances(cli_data_t *cli_data, char *argv[]); +static int cli_exec_schema(cli_data_t *cli_data, char *argv[]); + +cli_cmd_t cli_commands[] = { +// Name NumArgs Exec callback Usage String + { "help", 0, cli_exec_help, "help" }, + { "get", 1, cli_exec_get, "get [path-expr]" }, + { "set", 2, cli_exec_set, "set [path-expr] [value]"}, + { "add", 1, cli_exec_add, "add [object]"}, + { "del", 1, cli_exec_del, "del [path-expr]"}, + { "instances", 1, cli_exec_instances, "instances [path-expr]" }, + { "schema", 1, cli_exec_schema, "schema [path-expr]"}, +}; + +static int bbfdm_load_cli_config(cli_data_t *cli_data) +{ + cli_data->proto = BBFDM_BOTH; + cli_data->instance_mode = INSTANCE_MODE_NUMBER; + snprintf(cli_data->out_type, 8, "%s", "CLI"); + snprintf(cli_data->in_type, 8, "%s", "DotSO"); + return 0; +} + +static int cli_exec_help(cli_data_t *cli_data UNUSED, char *argv[] UNUSED) +{ + printf("Valid commands:\n"); + + // Print out the help usage of all commands + for (size_t i = 0; i < ARRAY_SIZE(cli_commands); i++) { + printf(" %s\n", cli_commands[i].usage); + } + + return EXIT_SUCCESS; +} + +static int in_dotso_out_cli_exec_get(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_GET_VALUE); + if (!err) { + struct dm_parameter *n; + + list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) { + printf("%s => %s\n", n->name, n->data); + } + } else { + printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_get(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_get(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int in_dotso_out_cli_exec_set(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + cli_data->bbf_ctx.in_value = argv[1]; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_SET_VALUE); + if (!err) { + printf("%s => Set value is successfully done\n", cli_data->bbf_ctx.in_param); + bbf_entry_restart_services(NULL, true); + } else { + printf("ERROR: %d retrieving %s => %s\n", err, cli_data->bbf_ctx.in_param, cli_data->bbf_ctx.in_value); + bbf_entry_revert_changes(NULL); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_set(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_set(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int in_dotso_out_cli_exec_add(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_ADD_OBJECT); + if (!err) { + printf("Added %s%s.\n", cli_data->bbf_ctx.in_param, cli_data->bbf_ctx.addobj_instance); + bbf_entry_restart_services(NULL, true); + } else { + printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param); + bbf_entry_revert_changes(NULL); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_add(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_add(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int in_dotso_out_cli_exec_del(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_DEL_OBJECT); + if (!err) { + printf("Deleted %s\n", cli_data->bbf_ctx.in_param); + bbf_entry_restart_services(NULL, true); + } else { + printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param); + bbf_entry_revert_changes(NULL); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_del(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_del(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int in_dotso_out_cli_exec_instances(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + cli_data->bbf_ctx.nextlevel = false; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_INSTANCES); + if (!err) { + struct dm_parameter *n; + + list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) { + printf("%s\n", n->name); + } + } else { + printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_instances(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_instances(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int in_dotso_out_cli_exec_schema(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + cli_data->bbf_ctx.in_param = argv[0]; + cli_data->bbf_ctx.nextlevel = false; + cli_data->bbf_ctx.iscommand = true; + cli_data->bbf_ctx.isevent = true; + cli_data->bbf_ctx.isinfo = true; + + err = bbf_entry_method(&cli_data->bbf_ctx, BBF_SCHEMA); + if (!err) { + struct dm_parameter *n; + + printf("\nDumping %s Schema...\n\n", cli_data->bbf_ctx.in_param); + + list_for_each_entry(n, &cli_data->bbf_ctx.list_parameter, list) { + int cmd = get_dm_type(n->type); + + printf("%s\n", n->name); + + if (cmd == DMT_COMMAND) { + if (n->data) { + const char **in, **out; + operation_args *args; + int i; + + args = (operation_args *) n->data; + in = args->in; + if (in) { + for (i = 0; in[i] != NULL; i++) + printf("%s input:%s\n", n->name, in[i]); + } + + out = args->out; + if (out) { + for (i = 0; out[i] != NULL; i++) + printf("%s output:%s\n", n->name, out[i]); + } + } + } else if (cmd == DMT_EVENT) { + if (n->data) { + event_args *ev; + + ev = (event_args *)n->data; + + if (ev->param) { + const char **in = ev->param; + + for (int i = 0; in[i] != NULL; i++) + printf("%s event_arg:%s\n", n->name, in[i]); + } + } + } + } + } else { + printf("ERROR: %d retrieving %s\n", err, cli_data->bbf_ctx.in_param); + err = EXIT_FAILURE; + } + + return err; +} + +static int cli_exec_schema(cli_data_t *cli_data, char *argv[]) +{ + int err = EXIT_SUCCESS; + + if (strcasecmp(cli_data->in_type, "DotSO") == 0 || strcasecmp(cli_data->in_type, "JSON") == 0) + err = in_dotso_out_cli_exec_schema(cli_data, argv); + else + err = EXIT_FAILURE; + + return err; +} + +static int cli_exec_command(cli_data_t *cli_data, int argc, char *argv[]) +{ + cli_cmd_t *cli_cmd = NULL; + int err = EXIT_SUCCESS; + + cli_data->cmd = argv[0]; + if (!cli_data->cmd || strlen(cli_data->cmd) == 0) { + return EXIT_FAILURE; + } + + bbfdm_load_deamon_config(); + bbf_ctx_init(&cli_data->bbf_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE); + if (DEAMON_DM_ROOT_OBJ == NULL) { + return EXIT_FAILURE; + } + + cli_data->bbf_ctx.dm_type = cli_data->proto; + cli_data->bbf_ctx.instance_mode = cli_data->instance_mode; + + for (size_t i = 0; i < ARRAY_SIZE(cli_commands); i++) { + cli_cmd = &cli_commands[i]; + if (strcmp(cli_data->cmd, cli_cmd->name) == 0) { + if (argc-1 < cli_cmd->num_args) { + printf("ERROR: Number of arguments for %s method is wrong(%d), it should be %d\n", cli_cmd->name, argc-1, cli_cmd->num_args); + cli_commands[0].exec_cmd(cli_data, NULL); + err = EXIT_FAILURE; + goto end; + } + + err = cli_cmd->exec_cmd(cli_data, &argv[1]); + break; + } + } + +end: + bbf_ctx_clean(&cli_data->bbf_ctx); + bbf_global_clean(DEAMON_DM_ROOT_OBJ); + return err; +} + +int bbfdm_cli_exec_command(int argc, char *argv[]) +{ + cli_data_t cli_data = {0}; + int err = EXIT_SUCCESS; + + // Exit if no command specified + if (argc < 1) { + printf("ERROR: command name not specified\n"); + return EXIT_FAILURE; + } + + memset(&cli_data, 0, sizeof(cli_data_t)); + err = bbfdm_load_cli_config(&cli_data); + if (err) { + return EXIT_FAILURE; + } + + err = cli_exec_command(&cli_data, argc, argv); + + return err; +} diff --git a/daemon/json_rpc/cli.h b/daemon/json_rpc/cli.h new file mode 100644 index 0000000000000000000000000000000000000000..8de5a90732d4ba5809e6d889843d144d356ee1ef --- /dev/null +++ b/daemon/json_rpc/cli.h @@ -0,0 +1,11 @@ +/* + * cli.c: Cli command for bbfdmd + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +int bbfdm_cli_exec_command(int argc, char *argv[]); diff --git a/daemon/json_rpc/common.c b/daemon/json_rpc/common.c new file mode 100644 index 0000000000000000000000000000000000000000..483983235278f243ec8a45c53d0e6eff7b192e1e --- /dev/null +++ b/daemon/json_rpc/common.c @@ -0,0 +1,152 @@ +/* + * common.c: Common utils of Get/Set/Operate handlers + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Vivek Dutta <vivek.dutta@iopsys.eu> + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include "common.h" +#include "get_helper.h" + +#define DEFAULT_LOG_LEVEL (2) + +static unsigned char gLogLevel = DEFAULT_LOG_LEVEL; + +// Logging utilities +void set_debug_level(unsigned char level) +{ + gLogLevel = level; +} + +void print_error(const char *format, ...) +{ + va_list arglist; + + if (gLogLevel < 1) + return; + + va_start(arglist, format); + vsyslog(LOG_ERR, format, arglist); + va_end(arglist); +} + +void print_warning(const char *format, ...) +{ + va_list arglist; + + if (gLogLevel < 2) + return; + + va_start(arglist, format); + vsyslog(LOG_WARNING, format, arglist); + va_end(arglist); +} + +void print_info(const char *format, ...) +{ + va_list arglist; + + if (gLogLevel < 3) + return; + + va_start(arglist, format); + vsyslog(LOG_INFO, format, arglist); + va_end(arglist); +} + +void print_debug(const char *format, ...) +{ + va_list arglist; + + if (gLogLevel < 4) + return; + + va_start(arglist, format); + vsyslog(LOG_DEBUG, format, arglist); + va_end(arglist); +} + + +bool is_str_eq(const char *s1, const char *s2) +{ + if (strcmp(s1, s2) == 0) + return true; + + return false; +} + +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; +} + + + +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; +} + +eParamType get_eparam_type(char *dm_type, int *err) +{ + *err = 0; + switch (get_dm_type(dm_type)) + { + case DMT_STRING: return PARAM_STRING; + case DMT_UNINT: return PARAM_UNSIGNED_INTEGER; + case DMT_INT: return PARAM_INTEGER; + case DMT_UNLONG: return PARAM_UNSIGNED_LONG; + case DMT_LONG: return PARAM_LONG; + case DMT_BOOL: return PARAM_BOOLEAN; + case DMT_HEXBIN: return PARAM_HEXBINARY; + case DMT_BASE64: return PARAM_BASE64; + default: break; + } + *err = -1; + + return 0; +} + diff --git a/daemon/json_rpc/common.h b/daemon/json_rpc/common.h new file mode 100644 index 0000000000000000000000000000000000000000..a25891331a7f2024dc028dfa3892c1c137c08919 --- /dev/null +++ b/daemon/json_rpc/common.h @@ -0,0 +1,64 @@ +#ifndef COMMON_H +#define COMMON_H + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <syslog.h> +#include <regex.h> +#include <sys/param.h> +#include <string.h> + +#include <json_hal_common.h> + +#include "libdmtree/dmapi.h" + +#define ROOT_NODE "Device." +#define BBF_ADD_EVENT "AddObj" +#define BBF_DEL_EVENT "DelObj" +#define BBF_EVENT "event" + +#define MAX_DM_KEY_LEN 256 +#define MAX_DM_PATH 1024 +#define MAX_DM_VALUE 4096 +#define DM_VALUE_SEP "," +#define DELIM '.' + +extern DMOBJ *DEAMON_DM_ROOT_OBJ; +extern DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2]; +extern DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE; + +bool is_str_eq(const char *s1, const char *s2); +void set_debug_level(unsigned char level); +void print_error(const char *format, ...); +void print_warning(const char *format, ...); +void print_info(const char *format, ...); +void print_debug(const char *format, ...); +bool get_boolean_string(char *value); + +int get_dm_type(char *dm_type); +eParamType get_eparam_type(char *dm_type, int *err); + +#define DEBUG(fmt, args...) \ + print_debug("[%s:%d]"fmt, __func__, __LINE__, ##args) + +#define INFO(fmt, args...) \ + print_info(fmt, ##args) + +#define ERR(fmt, args...) \ + print_error("[%s:%d] " fmt, __func__, __LINE__, ##args) + +#define WARNING(fmt, args...) \ + print_warning("[%s:%d] " fmt, __func__, __LINE__, ##args) + +// glibc doesn't guarantee a 0 termianted string on strncpy +// strncpy with always 0 terminated string +static inline void strncpyt(char *dst, const char *src, size_t n) +{ + if (n > 1) { + strncpy(dst, src, n - 1); + dst[n - 1] = 0; + } +} + +#endif /* COMMON_H */ diff --git a/daemon/json_rpc/event.c b/daemon/json_rpc/event.c new file mode 100644 index 0000000000000000000000000000000000000000..8873a451803e1e7ca884d786f408b93d375e197e --- /dev/null +++ b/daemon/json_rpc/event.c @@ -0,0 +1,93 @@ +/* + * event.c: event handler + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ +#include "libdmtree/dmcommon.h" +#include "event.h" +#include <unistd.h> + +#define FIREWALL_RULE_DATA "Device.Services.VoiceService.%d.X_RDK_Firewall_Rule_Data" +#define FIREWALL_RULE_DATA_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.X_RDK_Firewall_Rule_Data" + +int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply) +{ + int ret = RETURN_OK; + int param_index = 0; + hal_subscribe_event_request_t param_request; + + if (jmsg == NULL || jreply == NULL) { + ERR("event handler: Invalid memory"); + return RETURN_ERR; + } + + memset(¶m_request, 0, sizeof(param_request)); + + for (param_index = 0; param_index < param_count; param_index++) { + /* Unpack the request parameter */ + if (json_hal_get_subscribe_event_request((json_object *)jmsg, + param_index, ¶m_request) != RETURN_OK) { + INFO("Failed to get subscription data from the server"); + return RETURN_ERR; + } + + if (!match(param_request.name, FIREWALL_RULE_DATA_PATTERN)) { + ret = RETURN_ERR; + WARNING("Unexpected event [%s][%d]", param_request.name, (int)param_request.type); + } + else + INFO("Subscribed [%s][%d]", param_request.name, (int)param_request.type); + } + + ret = json_hal_add_result_status(jreply, ret == RETURN_OK ? RESULT_SUCCESS : + RESULT_FAILURE); + + INFO("[%s] Replly msg = %s", __FUNCTION__, + json_object_to_json_string_ext(jreply, JSON_C_TO_STRING_PRETTY)); + + return ret; +} + +/* Expected format of rule : enable/disable,protocol,port,ip; + Ex: 1,sip,5060,2a02:c69:fe02::4; + 1,sip,5060,2a02:c69:fe02::4;1,rtp,50000,2a02:c69:fe02::4; + 1,sip,5060,2a02:c69:fe02::4;0,rtp,50000,2a02:c69:fe02::4;1,rtp,50001,2a02:c69:fe02::4; */ +static void create_fw_rule_payload(char **buf, bool enable, char *protocol, int port, char *ip) +{ + dmasprintf(buf, "%d,%s,%d,%s;", enable, protocol, port, ip); +} + +int send_fw_rule_event(bool enable, char *protocol, int port, char *ip, int voice_service_idx) +{ + int ret = 0; + char *fw_rule_path = NULL; + char *fw_rule = NULL; + + create_fw_rule_payload(&fw_rule, enable, protocol, port, ip); + dmasprintf(&fw_rule_path, FIREWALL_RULE_DATA, voice_service_idx); + + ret = (json_hal_server_publish_event(fw_rule_path, fw_rule) == RETURN_OK) ? 0 : -1; + dmfree(fw_rule_path); + dmfree(fw_rule); + + return ret; +} + +int send_fw_rules_clear_event(int voice_service_idx) +{ + int ret = 0; + char *fw_rule_path = NULL; + char fw_rule[] = {0}; + + dmasprintf(&fw_rule_path, FIREWALL_RULE_DATA, voice_service_idx); + + ret = (json_hal_server_publish_event(fw_rule_path, fw_rule) == RETURN_OK) ? 0 : -1; + dmfree(fw_rule_path); + + return ret; +} + diff --git a/daemon/json_rpc/event.h b/daemon/json_rpc/event.h new file mode 100644 index 0000000000000000000000000000000000000000..39facd3b2f7634e123b36f1bb544449891a3c824 --- /dev/null +++ b/daemon/json_rpc/event.h @@ -0,0 +1,20 @@ +#ifndef EVENT_H +#define EVENT_H + +#include <json_hal_server.h> +#include "common.h" + +enum { + VOICE_CON_ENABLED, + VOICE_CON_PROTOCOL, + VOICE_CON_PORT, + VOICE_CON_IP, + _VOICE_CON_MAX +}; + +int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply); +int send_fw_rule_event(bool enable, char *protocol, int port, char *ip, int voice_service_idx); +int send_fw_rules_clear_event(int voice_service_idx); + +#endif /* EVENT_H */ + diff --git a/daemon/json_rpc/get.c b/daemon/json_rpc/get.c new file mode 100644 index 0000000000000000000000000000000000000000..91c78e3a22d094f6ba9f463438d4e899a263409e --- /dev/null +++ b/daemon/json_rpc/get.c @@ -0,0 +1,106 @@ +/* + * get.c: Get handler for bbfdmd + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include "get.h" +#include "get_helper.h" + +typedef int (resp_cb_t)(char *name, char *value, char *type, void *ctx); + +static int resp_cb(char *name, char *value, char *type, void *ctx) +{ + int ret; + hal_param_t param_response; + json_object *jreply = ctx; + + strncpyt(param_response.name, name, sizeof(param_response.name)); + + param_response.type = get_eparam_type(type, &ret); + if (ret) { + ERR("Unsupported parameter type %s for %s", type, name); + return -1; + } + + /* json rpc expects true/false value for boolean */ + if (param_response.type == PARAM_BOOLEAN) { + if (strncmp(value, "1", 2) == 0) { + strncpyt(param_response.value, "true", sizeof(param_response.value)); + } else if (strncmp(value, "0", 2) == 0) { + strncpyt(param_response.value, "false", sizeof(param_response.value)); + } else { + strncpyt(param_response.value, value, sizeof(param_response.value)); + } + } else { + strncpyt(param_response.value, value, sizeof(param_response.value)); + } + + if (json_hal_add_param(jreply, GET_RESPONSE_MESSAGE, ¶m_response) != RETURN_OK) { + ERR("Failed to add response for %s", name); + return -1; + } + + return 0; +} + +static int get_value(hal_param_t *params, resp_cb_t resp_cb, void *ctx) +{ + struct dmctx bbf_ctx; + struct dm_parameter *n = NULL; + int ret = -1; + + memset(&bbf_ctx, 0, sizeof(bbf_ctx)); + bbf_init(&bbf_ctx); + bbf_ctx.in_param = params->name; + bbf_ctx.enable_plugins = true; + + if ((ret = bbfdm_cmd_exec(&bbf_ctx, BBF_GET_VALUE))) { + ERR("Failed to get value for %s", params->name); + goto Exit; + } + + INFO("Preparing result for %s", params->name); + list_for_each_entry(n, &bbf_ctx.list_parameter, list) { + if (resp_cb(n->name, n->data, n->type, ctx)) { + goto Exit; + } + } + + ret = 0; +Exit: + bbf_cleanup(&bbf_ctx); + return ret; +} + +int bbfdm_get_value(const json_object *jmsg, int param_count, + json_object *jreply) +{ + int i; + hal_param_t param_request; + + if (jmsg == NULL || jreply == NULL) { + ERR("invalid parameter"); + return RETURN_ERR; + } + + for (i = 0; i < param_count; i++) { + /* Unpack the JSON and populate the data into request_param object */ + if (json_hal_get_param((json_object *)jmsg, i, GET_REQUEST_MESSAGE, + ¶m_request) != RETURN_OK) { + ERR("Failed to get parameter from json"); + return RETURN_ERR; + } + + if (get_value(¶m_request, resp_cb, jreply)) { + ERR("Failed to get parameter value for %s", param_request.name); + return RETURN_ERR; + } + } + + return RETURN_OK; +} diff --git a/daemon/json_rpc/get.h b/daemon/json_rpc/get.h new file mode 100644 index 0000000000000000000000000000000000000000..624f11dd5120110b6a190d9a4f444ac5d3ec4851 --- /dev/null +++ b/daemon/json_rpc/get.h @@ -0,0 +1,12 @@ +#ifndef GET_H +#define GET_H + +#include "common.h" +#include <json_hal_server.h> + + +int bbfdm_get_value(const json_object *jmsg, int param_count, + json_object *jreply); + +#endif /* GET_H */ + diff --git a/daemon/json_rpc/get_helper.c b/daemon/json_rpc/get_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..007bbff7d47095623685cab0b1d88abf2e20fd72 --- /dev/null +++ b/daemon/json_rpc/get_helper.c @@ -0,0 +1,92 @@ +/* + * get_helper.c: Get Fast handler for bbfdmd + * + * Copyright (C) 2019-2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Vivek Dutta <vivek.dutta@iopsys.eu> + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#define _XOPEN_SOURCE +#define _DEFAULT_SOURCE + +#include <time.h> +#include <setjmp.h> + +#include "get_helper.h" +#include "common.h" + +#include "libdmtree/dmentry.h" + + +DMOBJ *DEAMON_DM_ROOT_OBJ = NULL; +DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2] = {0}; +DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = NULL; + +// uloop.h does not have versions, below line is to use +// deprecated uloop_timeout_remaining for the time being +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +static jmp_buf gs_jump_location; +static bool gs_jump_called_by_bbf = false; + +void handle_pending_signal(int sig) +{ + if (gs_jump_called_by_bbf) { + siglongjmp(gs_jump_location, 1); + } + + ERR("Exception [%d] not cause by bbf dm, exit with error", sig); + exit(1); +} + +int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd) +{ + int fault = 0; + + if (bbf_ctx->in_param == NULL) + return USP_FAULT_INTERNAL_ERROR; + + if (sigsetjmp(gs_jump_location, 1) == 0) { + gs_jump_called_by_bbf = true; + fault = bbf_entry_method(bbf_ctx, cmd); + } else { + ERR("PID [%ld]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param); + fault = USP_FAULT_INTERNAL_ERROR; + } + + gs_jump_called_by_bbf = false; + + if (fault) + WARNING("Fault [%d => %d => %s]", fault, cmd, bbf_ctx->in_param); + + return fault; +} + +void bbf_init(struct dmctx *dm_ctx) +{ + bbf_ctx_init(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE); +} + +void bbf_cleanup(struct dmctx *dm_ctx) +{ + bbf_ctx_clean(dm_ctx); +} + +void bbf_sub_init(struct dmctx *dm_ctx) +{ + bbf_ctx_init_sub(dm_ctx, DEAMON_DM_ROOT_OBJ, DEAMON_DM_VENDOR_EXTENSION, DEAMON_DM_VENDOR_EXTENSION_EXCLUDE); +} + +void bbf_sub_cleanup(struct dmctx *dm_ctx) +{ + bbf_ctx_clean_sub(dm_ctx); +} + +void bbf_commit() +{ + bbf_entry_restart_services(NULL, true); +} + diff --git a/daemon/json_rpc/get_helper.h b/daemon/json_rpc/get_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..0ff7804c4a659c544b3298837c4f6e45dfaf9c63 --- /dev/null +++ b/daemon/json_rpc/get_helper.h @@ -0,0 +1,18 @@ +#ifndef GET_HELPER_H +#define GET_HELPER_H + +#include <libubox/blobmsg.h> +#include "common.h" +#include "libdmtree/dmbbf.h" + +void handle_pending_signal(int sig); + +int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd); + +void bbf_init(struct dmctx *dm_ctx); +void bbf_cleanup(struct dmctx *dm_ctx); +void bbf_sub_init(struct dmctx *dm_ctx); +void bbf_sub_cleanup(struct dmctx *dm_ctx); +void bbf_commit(); + +#endif /* GET_HELPER_H */ diff --git a/daemon/json_rpc/main.c b/daemon/json_rpc/main.c new file mode 100644 index 0000000000000000000000000000000000000000..a285a0a9e3aa776e5c72268155e901e143926875 --- /dev/null +++ b/daemon/json_rpc/main.c @@ -0,0 +1,229 @@ +/* + * main.c: Datamodel daemon + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <libubox/blobmsg.h> +#include <libubox/uloop.h> +#include <libubus.h> +#include <sys/prctl.h> +#include <sys/mman.h> + +#include "set.h" +#include "get.h" +#include "add_delete.h" +#include "event.h" +#include "get_helper.h" +#include "cli.h" +#include "libdmtree/dmentry.h" + +#define TELCOVOICEMGR_CONF_FILE "/etc/rdk/conf/telcovoice_manager_conf.json" + +extern struct list_head global_memhead; +extern DM_MAP_OBJ tDynamicObj[]; +extern DM_MAP_VENDOR tVendorExtension[]; + +static const char g_ubus_path[] = "voice.sip.data"; + +int rpc_handler_init() +{ + if (json_hal_server_init(TELCOVOICEMGR_CONF_FILE) != RETURN_OK) { + ERR("Failed to init HAL server"); + return -1; + } + + if (json_hal_server_register_action_callback("setParameters", + bbfdm_set_value) != RETURN_OK) { + ERR("Failed to register setParameters callback"); + goto Error; + } + + if (json_hal_server_register_action_callback("getParameters", + bbfdm_get_value) != RETURN_OK) { + ERR("Failed to register getParameters callback"); + goto Error; + } + + if (json_hal_server_register_action_callback("deleteObject", + bbfdm_del_object) != RETURN_OK) { + ERR("Failed to register deleteObject callback"); + goto Error; + } + if (json_hal_server_register_action_callback("subscribeEvent", + subs_event_handler) != RETURN_OK) { + ERR("Failed to register subscribeEvent callback"); + goto Error; + } + + if (json_hal_server_run() != RETURN_OK) { + ERR("Failed to run HAL server"); + goto Error; + } + + return 0; + +Error: + json_hal_server_terminate(); + return -1; +} + +int rpc_handler_uninit() +{ + if (json_hal_server_terminate() != RETURN_OK) { + ERR("Failed to terminate HAL server"); + return -1; + } + + return 0; +} + +static void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [options]\n", prog); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -c <command input> Run cli command\n"); + fprintf(stderr, " -h Displays this help\n"); + fprintf(stderr, "\n"); +} + +static void bbfdm_cleanup(void) +{ + bbf_global_clean(DEAMON_DM_ROOT_OBJ); +} + +int bbfdm_load_deamon_config(void) +{ + DEAMON_DM_ROOT_OBJ = (DMOBJ *)dm_dynamic_calloc(&global_memhead, 2, sizeof(DMOBJ)); + if (DEAMON_DM_ROOT_OBJ == NULL) { + fprintf(stderr, "ERROR: No Memory exists\n"); + return -1; + } + + char *node_obj = dm_dynamic_strdup(&global_memhead, tDynamicObj[0].path); + unsigned int len = strlen(node_obj); + + node_obj[len-1] = 0; + DEAMON_DM_ROOT_OBJ[0].obj = node_obj; + DEAMON_DM_ROOT_OBJ[0].nextobj = tDynamicObj[0].root_obj; + DEAMON_DM_ROOT_OBJ[0].leaf = tDynamicObj[0].root_leaf; + DEAMON_DM_ROOT_OBJ[0].permission = &DMREAD; + DEAMON_DM_ROOT_OBJ[0].bbfdm_type = BBFDM_BOTH; + + DEAMON_DM_VENDOR_EXTENSION[0] = tVendorExtension; + //DEAMON_DM_VENDOR_EXTENSION[1] = tVendorExtensionOverwrite; + //DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = tVendorExtensionExclude; + + return 0; +} + +static void program_exit(int ret) +{ + rpc_handler_uninit(); + bbfdm_cleanup(); + closelog(); + uloop_done(); + exit(ret); +} + +static void sig_handler(__attribute__((unused)) int signum) +{ + program_exit(0); +} + +static void signal_init() +{ + signal(SIGINT, sig_handler); +} + +static void voice_event_cb(struct ubus_context *ctx __attribute__((unused)), + struct ubus_event_handler *ev __attribute__((unused)), + const char *type, struct blob_attr *msg) +{ + const struct blobmsg_policy policy[] = { + [VOICE_CON_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL}, + [VOICE_CON_PROTOCOL] = { .name = "protocol", .type = BLOBMSG_TYPE_STRING}, + [VOICE_CON_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32}, + [VOICE_CON_IP] = { .name = "ip", .type = BLOBMSG_TYPE_STRING}, + }; + struct blob_attr *tb[_VOICE_CON_MAX]; + + if (type && strcmp(type, g_ubus_path) != 0) + return; + + if (blobmsg_parse(policy, _VOICE_CON_MAX, tb, blob_data(msg), blob_len(msg))){ + ERR("Failed to parse blob"); + return; + } + + send_fw_rule_event(blobmsg_get_bool(tb[VOICE_CON_ENABLED]), + blobmsg_get_string(tb[VOICE_CON_PROTOCOL]), + blobmsg_get_u32(tb[VOICE_CON_PORT]), + blobmsg_get_string(tb[VOICE_CON_IP]), 1); +} + +int main(int argc, char **argv) +{ + int err = 0, ch; + struct ubus_context *ubus_ctx = NULL; + struct ubus_event_handler add_event = {}; + + signal_init(); + + while ((ch = getopt(argc, argv, "h:c:")) != -1) { + switch (ch) { + case 'c': + err = bbfdm_cli_exec_command(argc-optind+1, &argv[optind-1]); + exit(err); + case 'h': + usage(argv[0]); + exit(0); + default: + break; + } + } + + openlog(argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); + + err = bbfdm_load_deamon_config(); + if (err) { + ERR("Failed to configure DM"); + goto Exit; + } + + err = rpc_handler_init(); + if (err) { + ERR("Voice HAL Server Initialization Failed"); + goto Exit; + } + + uloop_init(); + + ubus_ctx = ubus_connect(NULL); + if (!ubus_ctx) { + ERR("Failed to connect to ubus"); + return -1; + } + + ubus_add_uloop(ubus_ctx); + add_event.cb = voice_event_cb; + if (ubus_register_event_handler(ubus_ctx, &add_event, g_ubus_path)) + ERR("Failed to connect to ubus"); + + INFO("Waiting on uloop...."); + uloop_run(); + +Exit: + ubus_shutdown(ubus_ctx); + program_exit(err); + + return err; +} diff --git a/daemon/json_rpc/service_helper.c b/daemon/json_rpc/service_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..610332ea89e0cae5170f4c9d2f8583619d0f8b14 --- /dev/null +++ b/daemon/json_rpc/service_helper.c @@ -0,0 +1,70 @@ +/* + * service_helper.c: helper functions for managing services + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE file for license related information. + */ + +#include <string.h> +#include <signal.h> +#include <time.h> +#include <stdbool.h> +#include <errno.h> +#include <libubox/blobmsg.h> +#include "common.h" +#include "event.h" +#include "libdmtree/dmentry.h" +#include "libdmtree/dmcommon.h" + +#define SERVICE_RESTART_DELAY_SEC 10 + +static void timer_handler(union sigval sv) +{ + (void)sv; + + send_fw_rules_clear_event(1); + + dm_uci_init(); + bbf_entry_restart_services(NULL, false); + dm_uci_exit(); + + INFO("Restart services"); + + dmcmd("/bin/systemctl", 2, "restart", "voicemngr"); +#ifdef DM_ENABLE_DECT + dmcmd("/bin/systemctl", 2, "restart", "dectmngr"); +#endif + dmcmd("/bin/systemctl", 2, "restart", "asterisk"); +} + +int restart_services() +{ + static timer_t timerid; + static bool init; + struct sigevent sev; + struct itimerspec trigger; + + if (!init) { + memset(&sev, 0, sizeof(struct sigevent)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = &timer_handler; + + if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) != 0) { + ERR("Failed to create timer, err: %s (%d)", strerror(errno), errno); + return -1; + } + + init = true; + } + + // delay restart to accumulate all changes + memset(&trigger, 0, sizeof(struct itimerspec)); + trigger.it_value.tv_sec = SERVICE_RESTART_DELAY_SEC; + if (timer_settime(timerid, 0, &trigger, NULL) != 0) { + ERR("Failed to set timer, err: %s (%d)", strerror(errno), errno); + return -1; + } + + return 0; +} diff --git a/daemon/json_rpc/service_helper.h b/daemon/json_rpc/service_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..2700e97c7380459f90a2e83709bfe2ee48ddd956 --- /dev/null +++ b/daemon/json_rpc/service_helper.h @@ -0,0 +1,14 @@ +/* + * service_helper.h: helper functions for managing services + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * See LICENSE file for license related information. + */ + +#ifndef SERVICE_HELPER_H +#define SERVICE_HELPER_H + +int restart_services(); + +#endif /* SERVICE_HELPER_H */ diff --git a/daemon/json_rpc/set.c b/daemon/json_rpc/set.c new file mode 100644 index 0000000000000000000000000000000000000000..bff95536a7fc062b113d489b9d051e1ef07d3cd7 --- /dev/null +++ b/daemon/json_rpc/set.c @@ -0,0 +1,63 @@ +/* + * set.c: Set handler for bbfdmd + * + * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include "set.h" +#include "add_delete.h" +#include "get_helper.h" +#include "service_helper.h" + +int bbfdm_set_value(const json_object *jmsg, int param_count, + json_object *jreply) +{ + int i; + int fault; + hal_param_t param; + struct dmctx bbf_ctx; + + if (jmsg == NULL || jreply == NULL) { + ERR("setParameters cb: invalid memory"); + return RETURN_ERR; + } + + for (i = 0; i < param_count; i++) { + /* Unpack the JSON and polulate the data into request_param object */ + if (json_hal_get_param((json_object *)jmsg, i, SET_REQUEST_MESSAGE, + ¶m) != RETURN_OK) { + ERR("setParameters cb: failed get parameter"); + return RETURN_ERR; + } + + memset(&bbf_ctx, 0, sizeof(bbf_ctx)); + bbf_init(&bbf_ctx); + bbf_ctx.in_param = param.name; + bbf_ctx.in_value = param.value; + + fault = bbfdm_cmd_exec(&bbf_ctx, BBF_SET_VALUE); + /* Try to add a new object and try to set the value again */ + if (fault == FAULT_9005 && !bbfdm_add_object(&bbf_ctx)) + fault = bbfdm_cmd_exec(&bbf_ctx, BBF_SET_VALUE); + if (fault) + ERR("setParameters cb: failed setting (%s) (%s)", param.name, param.value); + + bbf_cleanup(&bbf_ctx); + + /* Pack the json response and reply back. */ + if (json_hal_add_result_status(jreply, fault == 0 ? RESULT_SUCCESS : + RESULT_FAILURE) != RETURN_OK) { + ERR("setParameters cb: failed setting status"); + return RETURN_ERR; + } + } + + restart_services(); + + return RETURN_OK; +} + diff --git a/daemon/json_rpc/set.h b/daemon/json_rpc/set.h new file mode 100644 index 0000000000000000000000000000000000000000..2375a66c124fbb820b496a9eb81fbd2a0cc4c220 --- /dev/null +++ b/daemon/json_rpc/set.h @@ -0,0 +1,11 @@ +#ifndef SET_H +#define SET_H + +#include "common.h" +#include <json_hal_server.h> + +int bbfdm_set_value(const json_object *jmsg, int param_count, + json_object *jreply); + +#endif /* SET_H */ + diff --git a/libdm/dmtree/servicesvoiceservice.c b/libdm/dmtree/servicesvoiceservice.c index 1336318151d6087ff36501f142a8d31b2c2cb116..71ad320c5b5e9ffddaafc12e7acceaadec0294cd 100644 --- a/libdm/dmtree/servicesvoiceservice.c +++ b/libdm/dmtree/servicesvoiceservice.c @@ -241,12 +241,49 @@ static int get_ServicesVoiceService_CallLogNumberOfEntries(char *refparam, struc return 0; } +static int get_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s; + + if ((s = is_dmmap_section_exist("dmmap_voice_hal_init", "general"))) + *value = dmuci_get_value_by_section_fallback_def(s, "init_done", "0"); + + return 0; +} + +static int set_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + struct uci_section *dmmap = NULL, *s = NULL, *stmp = NULL; + + switch (action) { + case VALUECHECK: + if (dm_validate_boolean(value)) + return FAULT_9007; + case VALUESET: + if (!(dmmap = is_dmmap_section_exist("dmmap_voice_hal_init", "general"))) { + dmuci_add_section("voice_hal_init", "general", &s); + dmuci_add_section_bbfdm("dmmap_voice_hal_init", "general", &dmmap); + dmuci_set_value_by_section(dmmap, "section_name", section_name(s)); + } + string_to_bool(value, &b); + uci_foreach_sections_safe("voice_hal_init", "general", stmp, s) { + get_dmmap_section_of_config_section("dmmap_voice_hal_init", "general", section_name(s), &dmmap); + dmuci_set_value_by_section(dmmap, "init_done", b ? "1" : "0"); + dmuci_set_value_by_section(s, "init_done", b ? "1" : "0"); + } + + return 0; + } + return 0; +} + /********************************************************************************************************************************** * OBJ & PARAM DEFINITION ***********************************************************************************************************************************/ DM_MAP_OBJ tDynamicObj[] = { /* parentobj, nextobject, parameter */ -{"Device.Services.", tServicesObj, NULL}, +{"Device.Services.", tServicesObj, tServicesVoiceHalParams}, {0} }; @@ -278,3 +315,7 @@ DMLEAF tServicesVoiceServiceParams[] = { {"CallLogNumberOfEntries", &DMREAD, DMT_UNINT, get_ServicesVoiceService_CallLogNumberOfEntries, NULL, BBFDM_BOTH}, {0} }; + +DMLEAF tServicesVoiceHalParams[] = { +{BBF_VENDOR_PREFIX"VoiceHalInit", &DMWRITE, DMT_BOOL, get_ServicesVoiceHalInit, set_ServicesVoiceHalInit, BBFDM_BOTH}, +}; diff --git a/libdm/dmtree/servicesvoiceservice.h b/libdm/dmtree/servicesvoiceservice.h index c1064e0563348a9bcab457b30a112bb5567b093b..6912ab8145ac88f1bb431df84ec4a7f222d8cc04 100644 --- a/libdm/dmtree/servicesvoiceservice.h +++ b/libdm/dmtree/servicesvoiceservice.h @@ -30,6 +30,7 @@ extern DMLEAF tServicesVoiceServiceVoIPProfileParams[]; extern DMLEAF tServicesVoiceServiceCodecProfileParams[]; extern DMOBJ tServicesVoiceServiceDECTObj[]; extern DMLEAF tServicesVoiceServiceDECTParams[]; +extern DMLEAF tServicesVoiceHalParams[]; int browseVoiceServiceSIPProviderInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int delObjVoiceServiceSIPProvider(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action);