/** * NEURON IIoT System for Industry 4.0 * Copyright (C) 2020-2022 EMQ Technologies Co., Ltd 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 as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ #include #include #include #include #include #include #include #include #include "event/event.h" #include "persist/persist.h" #include "utils/base64.h" #include "utils/log.h" #include "utils/time.h" #include "adapter.h" #include "adapter/adapter_internal.h" #include "adapter/driver/driver_internal.h" #include "adapter/storage.h" #include "argparse.h" #include "base/msg_internal.h" #include "errcodes.h" #include "node_manager.h" #include "plugin_manager.h" #include "storage.h" #include "subscribe.h" #include "manager.h" #include "manager_internal.h" // definition for adapter names #define DEFAULT_DASHBOARD_ADAPTER_NAME DEFAULT_DASHBOARD_PLUGIN_NAME static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data); inline static void reply(neu_manager_t *manager, neu_reqresp_head_t *header, void *data); inline static void forward_msg(neu_manager_t * manager, neu_reqresp_head_t *header, const char *node); inline static void forward_msg_copy(neu_manager_t * manager, neu_reqresp_head_t *header, const char * node); static void start_static_adapter(neu_manager_t *manager, const char *name); static int update_timestamp(void *usr_data); static void start_single_adapter(neu_manager_t *manager, const char *name, const char *plugin_name, bool display); static char *file_save_tmp(const char *data, const char *suffix); static bool mv_tmp_library_file(neu_plugin_kind_e kind, const char *tmp_path, const char *library); static bool mv_tmp_schema_file(const char *tmp_path, const char *schema); uint16_t neu_manager_get_port() { static uint16_t port = 10000; return port++; } neu_manager_t *neu_manager_create() { int rv = 0; neu_manager_t * manager = calloc(1, sizeof(neu_manager_t)); neu_event_io_param_t param = { .usr_data = (void *) manager, .cb = manager_loop, }; neu_event_timer_param_t timestamp_timer_param = { .second = 0, .millisecond = 10, .cb = update_timestamp, .type = NEU_EVENT_TIMER_NOBLOCK, }; manager->events = neu_event_new(); manager->plugin_manager = neu_plugin_manager_create(); manager->node_manager = neu_node_manager_create(); manager->subscribe_manager = neu_subscribe_manager_create(); manager->log_level = default_log_level; manager->server_fd = socket(AF_UNIX, SOCK_DGRAM, 0); assert(manager->server_fd > 0); struct timeval sock_timeout = { .tv_sec = 1, .tv_usec = 0, }; if (setsockopt(manager->server_fd, SOL_SOCKET, SO_SNDTIMEO, &sock_timeout, sizeof(sock_timeout)) < 0 || setsockopt(manager->server_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_timeout, sizeof(sock_timeout)) < 0) { assert(!"fail to set manager sock timeout"); } // abstract domain socket is a Linux extension, thus not portable. // use abstract domain socket here to avoid polluting the file system struct sockaddr_un local = { .sun_family = AF_UNIX, .sun_path = "#neuron-manager", }; local.sun_path[0] = '\0'; rv = bind(manager->server_fd, (struct sockaddr *) &local, sizeof(local)); assert(rv == 0); param.fd = manager->server_fd; manager->loop = neu_event_add_io(manager->events, param); manager->timestamp_lev_manager = 0; neu_metrics_init(); start_static_adapter(manager, DEFAULT_DASHBOARD_PLUGIN_NAME); if (manager_load_plugin(manager) != 0) { nlog_warn("load plugin error"); } UT_array *single_plugins = neu_plugin_manager_get_single(manager->plugin_manager); utarray_foreach(single_plugins, neu_resp_plugin_info_t *, plugin) { start_single_adapter(manager, plugin->single_name, plugin->name, plugin->display); } utarray_free(single_plugins); manager_load_node(manager); while (neu_node_manager_exist_uninit(manager->node_manager)) { usleep(1000 * 100); } manager_load_subscribe(manager); timestamp_timer_param.usr_data = (void *) manager; manager->timer_timestamp = neu_event_add_timer(manager->events, timestamp_timer_param); nlog_notice("manager start"); return manager; } void neu_manager_destroy(neu_manager_t *manager) { neu_req_node_init_t uninit = { 0 }; UT_array *addrs = neu_node_manager_get_addrs_all(manager->node_manager); neu_event_del_timer(manager->events, manager->timer_timestamp); utarray_foreach(addrs, struct sockaddr_un *, addr) { neu_msg_t *msg = neu_msg_new(NEU_REQ_NODE_UNINIT, NULL, &uninit); neu_reqresp_head_t *header = neu_msg_get_header(msg); strcpy(header->sender, "manager"); if (0 != neu_send_msg_to(manager->server_fd, addr, msg)) { nlog_error("manager -> %s uninit msg send fail", &addr->sun_path[1]); neu_msg_free(msg); } } utarray_free(addrs); while (1) { usleep(1000 * 100); if (neu_node_manager_size(manager->node_manager) == 0) { break; } } neu_subscribe_manager_destroy(manager->subscribe_manager); neu_node_manager_destroy(manager->node_manager); neu_plugin_manager_destroy(manager->plugin_manager); close(manager->server_fd); neu_event_del_io(manager->events, manager->loop); neu_event_close(manager->events); free(manager); nlog_notice("manager exit"); } static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) { int rv = 0; neu_manager_t * manager = (neu_manager_t *) usr_data; struct sockaddr_un src_addr = { 0 }; neu_msg_t * msg = NULL; neu_reqresp_head_t *header = NULL; if (type == NEU_EVENT_IO_CLOSED || type == NEU_EVENT_IO_HUP) { nlog_warn("manager socket(%d) recv closed or hup %d.", fd, type); return 0; } rv = neu_recv_msg_from(manager->server_fd, &src_addr, &msg); if (rv == -1) { nlog_warn("manager recv msg error: %s(%d)", strerror(errno), errno); return 0; } header = neu_msg_get_header(msg); nlog_info("manager recv msg from: %s to %s, type: %s", header->sender, header->receiver, neu_reqresp_type_string(header->type)); switch (header->type) { case NEU_REQ_NODE_INIT: { neu_req_node_init_t *init = (neu_req_node_init_t *) &header[1]; if (0 != neu_node_manager_update(manager->node_manager, init->node, src_addr)) { nlog_warn("bind node %s to src addr(%s) fail", init->node, &src_addr.sun_path[1]); neu_msg_free(msg); break; } if (init->state == NEU_NODE_RUNNING_STATE_RUNNING || init->state == NEU_NODE_RUNNING_STATE_STOPPED) { neu_adapter_t *adapter = neu_node_manager_find(manager->node_manager, init->node); neu_adapter_start(adapter); if (init->state == NEU_NODE_RUNNING_STATE_STOPPED) { neu_adapter_stop(adapter); } } nlog_notice("bind node %s to src addr(%s)", init->node, &src_addr.sun_path[1]); neu_msg_free(msg); break; } case NEU_REQ_ADD_PLUGIN: { neu_req_add_plugin_t *cmd = (neu_req_add_plugin_t *) &header[1]; neu_resp_error_t e = { 0 }; neu_plugin_kind_e kind = -1; char schema[64] = { 0 }; char buffer[65] = { 0 }; if (sscanf(cmd->library, "libplugin-%64s.so", buffer) != 1) { nlog_warn("library %s no conform", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_NAME_NOT_CONFORM; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (neu_persister_library_exists(cmd->library)) { nlog_warn("library %s had exited", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_NAME_CONFLICT; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } char *so_tmp_path = file_save_tmp(cmd->so_file, "so"); if (so_tmp_path == NULL) { nlog_warn("library %s so file save tmp fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_BODY_IS_WRONG; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } neu_plugin_instance_t ins = { 0 }; int error = NEU_ERR_SUCCESS; if (neu_plugin_manager_create_instance_by_path( manager->plugin_manager, so_tmp_path, &ins, &error)) { char module_name[64] = { 0 }; kind = ins.module->kind; strncpy(module_name, ins.module->module_name, sizeof(module_name)); strncpy(schema, ins.module->schema, sizeof(schema)); nlog_debug("library %s, module_name %s, schema:%s", cmd->library, module_name, schema); uint32_t major = NEU_GET_VERSION_MAJOR(ins.module->version); uint32_t minor = NEU_GET_VERSION_MINOR(ins.module->version); neu_plugin_manager_destroy_instance(manager->plugin_manager, &ins); if (NEU_VERSION_MAJOR != major || NEU_VERSION_MINOR != minor) { nlog_warn("library %s plugin version error, major:%d minor:%d", module_name, major, minor); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_VERSION_NOT_MATCH; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (neu_plugin_manager_exists(manager->plugin_manager, module_name)) { nlog_warn("%s module name had existed", module_name); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_ALREADY_EXIST; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } } else { nlog_warn("library %s so file is not a vaild file", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = error; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (kind != NEU_PLUGIN_KIND_CUSTOM && kind != NEU_PLUGIN_KIND_SYSTEM) { nlog_warn("library %s kind no support", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_KIND_NOT_SUPPORT; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } char *schema_tmp_path = file_save_tmp(cmd->schema_file, "json"); if (schema_tmp_path == NULL) { nlog_warn("library %s schema file save tmp fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_BODY_IS_WRONG; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!mv_tmp_library_file(kind, so_tmp_path, cmd->library)) { nlog_warn("library %s mv library tmp file fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_ADD_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!mv_tmp_schema_file(schema_tmp_path, schema)) { nlog_warn("library %s schema file save schema fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_ADD_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } error = neu_manager_add_plugin(manager, cmd->library); if (error == NEU_ERR_SUCCESS) { manager_strorage_plugin(manager); } free(so_tmp_path); free(cmd->so_file); free(cmd->schema_file); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = error; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } case NEU_REQ_DEL_PLUGIN: { neu_req_del_plugin_t *cmd = (neu_req_del_plugin_t *) &header[1]; neu_resp_error_t e = { 0 }; UT_array *nodes = neu_manager_get_nodes( manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, cmd->plugin, ""); if (nodes != NULL) { if (utarray_len(nodes) > 0) { utarray_free(nodes); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_IN_USE; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } utarray_free(nodes); } int error = neu_manager_del_plugin(manager, cmd->plugin); e.error = error; if (error == NEU_ERR_SUCCESS) { manager_strorage_plugin(manager); } header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } case NEU_REQ_UPDATE_PLUGIN: { neu_req_update_plugin_t *cmd = (neu_req_update_plugin_t *) &header[1]; neu_resp_error_t e = { 0 }; neu_plugin_kind_e kind = -1; char module_name[64] = { 0 }; char schema[64] = { 0 }; char buffer[65] = { 0 }; if (sscanf(cmd->library, "libplugin-%64s.so", buffer) != 1) { nlog_warn("library %s no conform", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_NAME_NOT_CONFORM; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!neu_persister_library_exists(cmd->library)) { nlog_warn("library %s no exited", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_NOT_FOUND; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } char *so_tmp_path = file_save_tmp(cmd->so_file, "so"); if (so_tmp_path == NULL) { nlog_warn("library %s so file save tmp fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_BODY_IS_WRONG; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } neu_plugin_instance_t ins = { 0 }; int error = NEU_ERR_SUCCESS; if (neu_plugin_manager_create_instance_by_path( manager->plugin_manager, so_tmp_path, &ins, &error)) { kind = ins.module->kind; strncpy(module_name, ins.module->module_name, sizeof(module_name)); strncpy(schema, ins.module->schema, sizeof(schema)); nlog_debug("library %s, module_name %s, schema:%s", cmd->library, module_name, schema); uint32_t major = NEU_GET_VERSION_MAJOR(ins.module->version); uint32_t minor = NEU_GET_VERSION_MINOR(ins.module->version); neu_plugin_manager_destroy_instance(manager->plugin_manager, &ins); if (NEU_VERSION_MAJOR != major || NEU_VERSION_MINOR != minor) { nlog_warn("library %s plugin version error, major:%d minor:%d", module_name, major, minor); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_VERSION_NOT_MATCH; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!neu_plugin_manager_create_instance_by_lib_name( manager->plugin_manager, cmd->library, &ins)) { nlog_warn("library %s not instance", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (strcmp(module_name, ins.module->module_name) != 0) { nlog_warn("library %s module name mismatch!", cmd->library); neu_plugin_manager_destroy_instance(manager->plugin_manager, &ins); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } neu_plugin_manager_destroy_instance(manager->plugin_manager, &ins); if (!neu_plugin_manager_exists(manager->plugin_manager, module_name)) { nlog_warn("library %s plugin name no existed", module_name); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_NOT_EXISTS; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } } else { nlog_warn("library %s so file is not a vaild file", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = error; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (kind != NEU_PLUGIN_KIND_CUSTOM && kind != NEU_PLUGIN_KIND_SYSTEM) { nlog_warn("library %s kind no support", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_MODULE_KIND_NOT_SUPPORT; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } char *schema_tmp_path = file_save_tmp(cmd->schema_file, "json"); if (schema_tmp_path == NULL) { nlog_warn("library %s schema file save tmp fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_BODY_IS_WRONG; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } UT_array *nodes = neu_manager_get_nodes( manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, module_name, ""); if (nodes != NULL) { if (utarray_len(nodes) > 0) { utarray_free(nodes); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); nlog_warn("library %s is using", cmd->library); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_IN_USE; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } utarray_free(nodes); } if (!neu_plugin_manager_remove_library(manager->plugin_manager, cmd->library)) { nlog_warn("library %s src file remove fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!mv_tmp_library_file(kind, so_tmp_path, cmd->library)) { nlog_warn("library %s mv library tmp file fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (!mv_tmp_schema_file(schema_tmp_path, schema)) { nlog_warn("library %s schema file save schema fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } if (neu_plugin_manager_update(manager->plugin_manager, cmd->library) != NEU_ERR_SUCCESS) { nlog_warn("update library %s fail", cmd->library); free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_LIBRARY_UPDATE_FAIL; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } free(cmd->so_file); free(cmd->schema_file); free(so_tmp_path); free(schema_tmp_path); header->type = NEU_RESP_ERROR; e.error = NEU_ERR_SUCCESS; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } case NEU_REQ_GET_PLUGIN: { UT_array * plugins = neu_manager_get_plugins(manager); neu_resp_get_plugin_t resp = { .plugins = plugins }; header->type = NEU_RESP_GET_PLUGIN; strcpy(header->receiver, header->sender); reply(manager, header, &resp); break; } case NEU_REQ_ADD_NODE: { neu_req_add_node_t *cmd = (neu_req_add_node_t *) &header[1]; int error = neu_manager_add_node(manager, cmd->node, cmd->plugin, cmd->setting, false, false); neu_resp_error_t e = { .error = error }; if (error == NEU_ERR_SUCCESS) { manager_storage_add_node(manager, cmd->node); if (cmd->setting) { adapter_storage_setting(cmd->node, cmd->setting); } } neu_req_add_node_fini(cmd); header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } case NEU_REQ_UPDATE_NODE: { neu_req_update_node_t *cmd = (neu_req_update_node_t *) &header[1]; neu_resp_error_t e = { 0 }; if (NULL == neu_node_manager_find(manager->node_manager, cmd->node)) { e.error = NEU_ERR_NODE_NOT_EXIST; } else if (NULL != neu_node_manager_find(manager->node_manager, cmd->new_name)) { // this also makes renaming to the original name an error e.error = NEU_ERR_NODE_EXIST; } if (0 == e.error) { header->type = NEU_REQ_NODE_RENAME; forward_msg(manager, header, header->receiver); } else { header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } break; } case NEU_REQ_DEL_NODE: { neu_req_del_node_t *cmd = (neu_req_del_node_t *) &header[1]; neu_resp_error_t error = { 0 }; neu_adapter_t * adapter = neu_node_manager_find(manager->node_manager, cmd->node); bool single = neu_node_manager_is_single(manager->node_manager, cmd->node); strcpy(header->receiver, cmd->node); if (adapter == NULL) { error.error = NEU_ERR_NODE_NOT_EXIST; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &error); break; } if (single) { error.error = NEU_ERR_NODE_NOT_ALLOW_DELETE; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &error); break; } manager_storage_del_node(manager, cmd->node); if (neu_adapter_get_type(adapter) == NEU_NA_TYPE_APP) { UT_array *subscriptions = neu_subscribe_manager_get( manager->subscribe_manager, cmd->node, NULL, NULL); neu_subscribe_manager_unsub_all(manager->subscribe_manager, cmd->node); utarray_foreach(subscriptions, neu_resp_subscribe_info_t *, sub) { // NOTE: neu_req_unsubscribe_t and neu_resp_subscribe_info_t // have compatible memory layout msg = neu_msg_new(NEU_REQ_UNSUBSCRIBE_GROUP, NULL, sub); if (NULL == msg) { break; } neu_reqresp_head_t *hd = neu_msg_get_header(msg); strcpy(hd->receiver, sub->driver); strcpy(hd->sender, "manager"); forward_msg(manager, hd, hd->receiver); } utarray_free(subscriptions); } neu_reqresp_node_deleted_t resp = { 0 }; strcpy(resp.node, header->receiver); header->type = NEU_REQ_NODE_UNINIT; forward_msg(manager, header, header->receiver); if (neu_adapter_get_type(adapter) == NEU_NA_TYPE_DRIVER) { UT_array *apps = neu_subscribe_manager_find_by_driver( manager->subscribe_manager, resp.node); utarray_foreach(apps, neu_app_subscribe_t *, app) { msg = neu_msg_new(NEU_REQRESP_NODE_DELETED, NULL, &resp); if (NULL == msg) { break; } header = neu_msg_get_header(msg); strcpy(header->receiver, app->app_name); strcpy(header->sender, "manager"); reply(manager, header, &resp); } utarray_free(apps); } break; } case NEU_RESP_NODE_UNINIT: { neu_resp_node_uninit_t *cmd = (neu_resp_node_uninit_t *) &header[1]; neu_manager_del_node(manager, cmd->node); if (strlen(header->receiver) > 0 && strcmp(header->receiver, "manager") != 0) { neu_resp_error_t error = { 0 }; header->type = NEU_RESP_ERROR; reply(manager, header, &error); } else { neu_msg_free(msg); } break; } case NEU_REQ_GET_NODE: { neu_req_get_node_t *cmd = (neu_req_get_node_t *) &header[1]; UT_array * nodes = neu_manager_get_nodes(manager, cmd->type, cmd->plugin, cmd->node); neu_resp_get_node_t resp = { .nodes = nodes }; header->type = NEU_RESP_GET_NODE; strcpy(header->receiver, header->sender); reply(manager, header, &resp); break; } case NEU_REQ_SUBSCRIBE_GROUP: { neu_req_subscribe_t *cmd = (neu_req_subscribe_t *) &header[1]; neu_resp_error_t error = { 0 }; uint16_t app_port = 0; error.error = neu_manager_subscribe(manager, cmd->app, cmd->driver, cmd->group, cmd->params, &app_port); if (error.error == NEU_ERR_SUCCESS) { cmd->port = app_port; forward_msg_copy(manager, header, cmd->app); forward_msg_copy(manager, header, cmd->driver); manager_storage_subscribe(manager, cmd->app, cmd->driver, cmd->group, cmd->params); } else { free(cmd->params); } header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &error); break; } case NEU_REQ_SUBSCRIBE_GROUPS: { neu_req_subscribe_groups_t *cmd = (neu_req_subscribe_groups_t *) &header[1]; neu_resp_error_t error = { 0 }; for (uint16_t i = 0; i < cmd->n_group; ++i) { neu_req_subscribe_group_info_t *info = &cmd->groups[i]; error.error = neu_manager_subscribe(manager, cmd->app, info->driver, info->group, info->params, &info->port); if (0 != error.error) { break; } error.error = neu_manager_send_subscribe(manager, cmd->app, info->driver, info->group, info->port, info->params); if (0 != error.error) { break; } manager_storage_subscribe(manager, cmd->app, info->driver, info->group, info->params); } neu_req_subscribe_groups_fini(cmd); header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &error); break; } case NEU_REQ_UPDATE_SUBSCRIBE_GROUP: { neu_req_subscribe_t *cmd = (neu_req_subscribe_t *) &header[1]; neu_resp_error_t error = { 0 }; error.error = neu_manager_update_subscribe( manager, cmd->app, cmd->driver, cmd->group, cmd->params); if (error.error == NEU_ERR_SUCCESS) { forward_msg_copy(manager, header, cmd->app); manager_storage_update_subscribe(manager, cmd->app, cmd->driver, cmd->group, cmd->params); } else { free(cmd->params); } header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &error); break; } case NEU_REQ_UNSUBSCRIBE_GROUP: { neu_req_unsubscribe_t *cmd = (neu_req_unsubscribe_t *) &header[1]; neu_resp_error_t error = { 0 }; error.error = neu_manager_unsubscribe(manager, cmd->app, cmd->driver, cmd->group); if (error.error == NEU_ERR_SUCCESS) { forward_msg_copy(manager, header, cmd->app); forward_msg_copy(manager, header, cmd->driver); manager_storage_unsubscribe(manager, cmd->app, cmd->driver, cmd->group); } header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &error); break; } case NEU_REQ_GET_SUBSCRIBE_GROUP: { neu_req_get_subscribe_group_t *cmd = (neu_req_get_subscribe_group_t *) &header[1]; UT_array *groups = neu_manager_get_sub_group_deep_copy( manager, cmd->app, cmd->driver, cmd->group); neu_resp_get_subscribe_group_t resp = { .groups = groups }; strcpy(header->receiver, header->sender); header->type = NEU_RESP_GET_SUBSCRIBE_GROUP; reply(manager, header, &resp); break; } case NEU_REQ_GET_SUB_DRIVER_TAGS: { neu_req_get_sub_driver_tags_t *cmd = (neu_req_get_sub_driver_tags_t *) &header[1]; neu_resp_get_sub_driver_tags_t resp = { 0 }; UT_array *groups = neu_manager_get_sub_group(manager, cmd->app); utarray_new(resp.infos, neu_resp_get_sub_driver_tags_info_icd()); utarray_foreach(groups, neu_resp_subscribe_info_t *, info) { neu_resp_get_sub_driver_tags_info_t in = { 0 }; neu_adapter_t * driver = neu_node_manager_find(manager->node_manager, info->driver); assert(driver != NULL); strcpy(in.driver, info->driver); strcpy(in.group, info->group); neu_adapter_driver_get_value_tag((neu_adapter_driver_t *) driver, info->group, &in.tags); utarray_push_back(resp.infos, &in); } utarray_free(groups); strcpy(header->receiver, header->sender); header->type = NEU_RESP_GET_SUB_DRIVER_TAGS; reply(manager, header, &resp); break; } case NEU_REQ_GET_NODES_STATE: { neu_resp_get_nodes_state_t resp = { 0 }; UT_array *states = neu_node_manager_get_state(manager->node_manager); neu_nodes_state_t *p_state = NULL; while ( (p_state = (neu_nodes_state_t *) utarray_next(states, p_state))) { p_state->sub_group_count = neu_subscribe_manager_group_count( manager->subscribe_manager, p_state->node); } resp.states = utarray_clone(states); resp.core_level = manager->log_level; strcpy(header->receiver, header->sender); strcpy(header->sender, "manager"); header->type = NEU_RESP_GET_NODES_STATE; reply(manager, header, &resp); utarray_free(states); break; } case NEU_REQ_GET_DRIVER_GROUP: { neu_resp_get_driver_group_t resp = { 0 }; resp.groups = neu_manager_get_driver_group(manager); strcpy(header->receiver, header->sender); strcpy(header->sender, "manager"); header->type = NEU_RESP_GET_DRIVER_GROUP; reply(manager, header, &resp); break; } case NEU_REQ_GET_GROUP: case NEU_REQ_GET_NODE_SETTING: case NEU_REQ_READ_GROUP: case NEU_REQ_WRITE_TAG: case NEU_REQ_WRITE_TAGS: case NEU_REQ_WRITE_GTAGS: case NEU_REQ_GET_TAG: case NEU_REQ_NODE_CTL: case NEU_REQ_ADD_GROUP: { if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { if (NEU_REQ_READ_GROUP == header->type) { neu_req_read_group_fini((neu_req_read_group_t *) &header[1]); } else if (NEU_REQ_WRITE_TAG == header->type) { neu_req_write_tag_fini((neu_req_write_tag_t *) &header[1]); } else if (NEU_REQ_WRITE_TAGS == header->type) { neu_req_write_tags_fini((neu_req_write_tags_t *) &header[1]); } else if (NEU_REQ_WRITE_GTAGS == header->type) { neu_req_write_gtags_fini((neu_req_write_gtags_t *) &header[1]); } neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_REQ_PRGFILE_PROCESS: case NEU_REQ_PRGFILE_UPLOAD: case NEU_REQ_SCAN_TAGS: case NEU_REQ_GET_NODE_STATE: { if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_RESP_NODE_RENAME: { neu_resp_node_rename_t *resp = (neu_resp_node_rename_t *) &header[1]; if (0 == resp->error) { neu_manager_update_node_name(manager, resp->node, resp->new_name); manager_storage_update_node(manager, resp->node, resp->new_name); if (neu_node_manager_is_driver(manager->node_manager, resp->new_name)) { UT_array *apps = neu_subscribe_manager_find_by_driver( manager->subscribe_manager, resp->new_name); // notify app node about driver renaming utarray_foreach(apps, neu_app_subscribe_t *, app) { header->type = NEU_REQ_UPDATE_NODE; forward_msg_copy(manager, header, app->app_name); } utarray_free(apps); } } neu_resp_error_t e = { .error = resp->error }; header->type = NEU_RESP_ERROR; reply(manager, header, &e); break; } case NEU_RESP_UPDATE_DRIVER_GROUP: { neu_resp_update_group_t *resp = (neu_resp_update_group_t *) &header[1]; if (0 == resp->error) { neu_manager_update_group_name(manager, resp->driver, resp->group, resp->new_name); UT_array *apps = neu_subscribe_manager_find( manager->subscribe_manager, resp->driver, resp->new_name); if (NULL != apps) { // notify app node about group renaming utarray_foreach(apps, neu_app_subscribe_t *, app) { header->type = NEU_REQ_UPDATE_GROUP; forward_msg_copy(manager, header, app->app_name); } utarray_free(apps); } } neu_resp_error_t e = { .error = resp->error }; header->type = NEU_RESP_ERROR; reply(manager, header, &e); break; } case NEU_REQ_UPDATE_GROUP: { neu_resp_error_t e = { 0 }; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { e.error = NEU_ERR_NODE_NOT_EXIST; } else if (!neu_node_manager_is_driver(manager->node_manager, header->receiver)) { e.error = NEU_ERR_GROUP_NOT_ALLOW; } else { header->type = NEU_REQ_UPDATE_DRIVER_GROUP; forward_msg(manager, header, header->receiver); } if (e.error) { header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } break; } case NEU_REQ_DEL_GROUP: { neu_req_del_group_t *cmd = (neu_req_del_group_t *) &header[1]; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { UT_array *apps = neu_subscribe_manager_find( manager->subscribe_manager, cmd->driver, cmd->group); forward_msg(manager, header, header->receiver); neu_subscribe_manager_remove(manager->subscribe_manager, cmd->driver, cmd->group); if (NULL == apps) { break; } // notify app node about group deletion utarray_foreach(apps, neu_app_subscribe_t *, app) { forward_msg_copy(manager, header, app->app_name); } utarray_free(apps); } break; } case NEU_REQ_DEL_TAG: { neu_req_del_tag_t *cmd = (neu_req_del_tag_t *) &header[1]; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { for (int i = 0; i < cmd->n_tag; i++) { free(cmd->tags[i]); } free(cmd->tags); neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_REQ_UPDATE_TAG: case NEU_REQ_ADD_TAG: { neu_req_add_tag_t *cmd = (neu_req_add_tag_t *) &header[1]; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { for (int i = 0; i < cmd->n_tag; i++) { neu_tag_fini(&cmd->tags[i]); } free(cmd->tags); neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_REQ_ADD_GTAG: { neu_req_add_gtag_t *cmd = (neu_req_add_gtag_t *) &header[1]; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { for (int i = 0; i < cmd->n_group; i++) { for (int j = 0; j < cmd->groups[i].n_tag; j++) { neu_tag_fini(&cmd->groups[i].tags[j]); } free(cmd->groups[i].tags); } free(cmd->groups); neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_REQ_NODE_SETTING: { neu_req_node_setting_t *cmd = (neu_req_node_setting_t *) &header[1]; if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { free(cmd->setting); neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } break; } case NEU_RESP_ADD_TAG: case NEU_RESP_ADD_GTAG: case NEU_RESP_UPDATE_TAG: case NEU_RESP_GET_TAG: case NEU_RESP_GET_GROUP: case NEU_RESP_GET_NODE_SETTING: case NEU_RESP_ERROR: case NEU_RESP_READ_GROUP: case NEU_RESP_PRGFILE_PROCESS: case NEU_RESP_SCAN_TAGS: forward_msg(manager, header, header->receiver); break; case NEU_RESP_GET_NODE_STATE: { neu_resp_get_node_state_t *resp = (neu_resp_get_node_state_t *) &header[1]; neu_adapter_t *adapter_node = neu_node_manager_find(manager->node_manager, header->sender); resp->sub_group_count = neu_subscribe_manager_group_count( manager->subscribe_manager, header->sender); resp->is_driver = (adapter_node->module->type == NEU_NA_TYPE_DRIVER) ? true : false; resp->core_level = manager->log_level; forward_msg(manager, header, header->receiver); break; } case NEU_REQ_ADD_DRIVERS: { neu_req_driver_array_t *cmd = (neu_req_driver_array_t *) &header[1]; neu_resp_error_t e = { 0 }; e.error = neu_manager_add_drivers(manager, cmd); if (NEU_ERR_SUCCESS == e.error) { for (uint16_t i = 0; i < cmd->n_driver; ++i) { neu_req_driver_t *driver = &cmd->drivers[i]; manager_storage_add_node(manager, driver->node); adapter_storage_setting(driver->node, driver->setting); for (uint16_t j = 0; j < driver->n_group; j++) { adapter_storage_add_group(driver->node, driver->groups[j].group, driver->groups[j].interval); adapter_storage_add_tags( driver->node, driver->groups[j].group, driver->groups[j].tags, driver->groups[j].n_tag); } } } neu_req_driver_array_fini(cmd); header->type = NEU_RESP_ERROR; strcpy(header->receiver, header->sender); reply(manager, header, &e); break; } case NEU_REQ_UPDATE_LOG_LEVEL: { neu_req_update_log_level_t *cmd = (neu_req_update_log_level_t *) &header[1]; if (cmd->core) { manager->log_level = cmd->log_level; nlog_level_change(manager->log_level); } if (strlen(cmd->node) > 0) { if (neu_node_manager_find(manager->node_manager, header->receiver) == NULL) { neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { forward_msg(manager, header, header->receiver); } } else { if (cmd->core) { neu_resp_error_t e = { .error = NEU_ERR_SUCCESS }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } else { neu_resp_error_t e = { .error = NEU_ERR_PARAM_IS_WRONG }; header->type = NEU_RESP_ERROR; neu_msg_exchange(header); reply(manager, header, &e); } } break; } default: assert(false); break; } return 0; } inline static void forward_msg_copy(neu_manager_t * manager, neu_reqresp_head_t *header, const char * node) { neu_msg_t *msg = neu_msg_copy((neu_msg_t *) header); forward_msg(manager, neu_msg_get_header(msg), node); } static void start_static_adapter(neu_manager_t *manager, const char *name) { neu_adapter_t * adapter = NULL; neu_plugin_instance_t instance = { 0 }; neu_adapter_info_t adapter_info = { .name = name, }; neu_plugin_manager_load_static(manager->plugin_manager, name, &instance); adapter_info.handle = instance.handle; adapter_info.module = instance.module; adapter = neu_adapter_create(&adapter_info, true); neu_node_manager_add_static(manager->node_manager, adapter); neu_adapter_init(adapter, false); neu_adapter_start(adapter); } static void start_single_adapter(neu_manager_t *manager, const char *name, const char *plugin_name, bool display) { neu_adapter_t * adapter = NULL; neu_plugin_instance_t instance = { 0 }; neu_adapter_info_t adapter_info = { .name = name, }; if (0 != neu_plugin_manager_create_instance(manager->plugin_manager, plugin_name, &instance)) { return; } adapter_info.handle = instance.handle; adapter_info.module = instance.module; adapter = neu_adapter_create(&adapter_info, true); neu_node_manager_add_single(manager->node_manager, adapter, display); if (display) { manager_storage_add_node(manager, name); } neu_adapter_init(adapter, false); neu_adapter_start_single(adapter); } inline static void reply(neu_manager_t *manager, neu_reqresp_head_t *header, void *data) { neu_msg_gen(header, data); struct sockaddr_un addr = neu_node_manager_get_addr(manager->node_manager, header->receiver); neu_reqresp_type_e t = header->type; void * ctx = header->ctx; char receiver[NEU_NODE_NAME_LEN] = { 0 }; strncpy(receiver, header->receiver, sizeof(receiver)); neu_msg_t *msg = (neu_msg_t *) header; int ret = neu_send_msg_to(manager->server_fd, &addr, msg); if (0 == ret) { nlog_notice("reply %s to %s(%s) %p", neu_reqresp_type_string(t), receiver, &addr.sun_path[1], ctx); } else { nlog_warn("reply %s to %s, error: %d", neu_reqresp_type_string(t), receiver, ret); neu_msg_free(msg); } } static int update_timestamp(void *usr_data) { (void) usr_data; global_timestamp = neu_time_ms(); return 0; } static char *file_save_tmp(const char *data, const char *suffix) { int d_len = 0; char *file = (char *) neu_decode64(&d_len, data); if (file == NULL) { nlog_warn("library so file decode64 ret is NULL"); return NULL; } if (d_len == 0) { nlog_warn("library so file decode64 len is 0"); free(file); return NULL; } char *tmp_path = neu_persister_save_file_tmp(file, d_len, suffix); if (tmp_path == NULL) { free(file); return NULL; } free(file); return tmp_path; } static bool mv_tmp_library_file(neu_plugin_kind_e kind, const char *tmp_path, const char *library) { char file_name[128] = { 0 }; char path_name[128] = { 0 }; if (kind == NEU_PLUGIN_KIND_CUSTOM) { snprintf(file_name, sizeof(file_name), "%s/custom/%s", g_plugin_dir, library); snprintf(path_name, sizeof(path_name), "%s/custom", g_plugin_dir); } else if (kind == NEU_PLUGIN_KIND_SYSTEM) { snprintf(file_name, sizeof(file_name), "%s/system/%s", g_plugin_dir, library); snprintf(path_name, sizeof(path_name), "%s/system", g_plugin_dir); } else { return false; } struct stat st; if (stat(path_name, &st) == -1) { if (mkdir(path_name, 0700) == -1) { nlog_error("%s mkdir fail", path_name); return false; } } if (rename(tmp_path, file_name) != 0) { nlog_error("%s rename %s fail, err:%s", tmp_path, file_name, strerror(errno)); return false; } else { return true; } return false; } static bool mv_tmp_schema_file(const char *tmp_path, const char *schema) { char file_name[128] = { 0 }; snprintf(file_name, sizeof(file_name), "%s/schema/%s.json", g_plugin_dir, schema); if (rename(tmp_path, file_name) != 0) { nlog_error("%s rename %s fail, err:%s", tmp_path, file_name, strerror(errno)); return false; } else { return true; } return false; }