/** Configuration parser. * * @author Steffen Vogel * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. * Unauthorized copying of this file, via any medium is strictly prohibited. *********************************************************************************/ #include #include #include "utils.h" #include "list.h" #include "if.h" #include "cfg.h" #include "node.h" #include "path.h" #include "hooks.h" #include "file.h" #ifdef ENABLE_SOCKET #include "socket.h" #endif #ifdef ENABLE_GTFPGA #include "gtfpga.h" #endif #ifdef ENABLE_OPAL_ASYNC #include "opal.h" #endif int config_parse(const char *filename, config_t *cfg, struct settings *set, struct list *nodes, struct list *paths) { config_set_auto_convert(cfg, 1); int ret = strcmp("-", filename) ? config_read_file(cfg, filename) : config_read(cfg, stdin); if (ret != CONFIG_TRUE) error("Failed to parse configuration: %s in %s:%d", config_error_text(cfg), config_error_file(cfg) ? config_error_file(cfg) : filename, config_error_line(cfg) ); config_setting_t *cfg_root = config_root_setting(cfg); /* Parse global settings */ if (set) { if (!cfg_root || !config_setting_is_group(cfg_root)) error("Missing global section in config file: %s", filename); config_parse_global(cfg_root, set); } /* Parse nodes */ if (nodes) { config_setting_t *cfg_nodes = config_setting_get_member(cfg_root, "nodes"); if (!cfg_nodes || !config_setting_is_group(cfg_nodes)) error("Missing node section in config file: %s", filename); for (int i = 0; i < config_setting_length(cfg_nodes); i++) { config_setting_t *cfg_node = config_setting_get_elem(cfg_nodes, i); config_parse_node(cfg_node, nodes, set); } } /* Parse paths */ if (paths) { config_setting_t *cfg_paths = config_setting_get_member(cfg_root, "paths"); if (!cfg_paths || !config_setting_is_list(cfg_paths)) error("Missing path section in config file: %s", filename); for (int i = 0; i < config_setting_length(cfg_paths); i++) { config_setting_t *cfg_path = config_setting_get_elem(cfg_paths, i); config_parse_path(cfg_path, paths, nodes, set); } } return 0; } int config_parse_global(config_setting_t *cfg, struct settings *set) { config_setting_lookup_int(cfg, "affinity", &set->affinity); config_setting_lookup_int(cfg, "priority", &set->priority); config_setting_lookup_int(cfg, "debug", &set->debug); config_setting_lookup_float(cfg, "stats", &set->stats); log_setlevel(set->debug); return 0; } int config_parse_path(config_setting_t *cfg, struct list *paths, struct list *nodes, struct settings *set) { const char *in; int enabled; int reverse; struct path *p = path_create(); /* Input node */ config_setting_t *cfg_in = config_setting_get_member(cfg, "in"); if (!cfg_in || config_setting_type(cfg_in) != CONFIG_TYPE_STRING) cerror(cfg, "Invalid input node for path"); in = config_setting_get_string(cfg_in); p->in = list_lookup(nodes, in); if (!p->in) cerror(cfg_in, "Invalid input node '%s'", in); /* Output node(s) */ config_setting_t *cfg_out = config_setting_get_member(cfg, "out"); if (cfg_out) config_parse_nodelist(cfg_out, &p->destinations, nodes); if (list_length(&p->destinations) >= 1) p->out = (struct node *) list_first(&p->destinations); else cerror(cfg, "Missing output node for path"); /* Optional settings */ config_setting_t *cfg_hook = config_setting_get_member(cfg, "hook"); if (cfg_hook) config_parse_hooklist(cfg_hook, p->hooks); if (!config_setting_lookup_bool(cfg, "enabled", &enabled)) enabled = 1; if (!config_setting_lookup_bool(cfg, "reverse", &reverse)) reverse = 0; if (!config_setting_lookup_float(cfg, "rate", &p->rate)) p->rate = 0; /* disabled */ if (!config_setting_lookup_int(cfg, "poolsize", &p->poolsize)) p->poolsize = DEFAULT_POOLSIZE; p->cfg = cfg; if (enabled) { p->in->refcnt++; p->in->vt->refcnt++; list_foreach(struct node *node, &p->destinations) { node->refcnt++; node->vt->refcnt++; } if (reverse) { if (list_length(&p->destinations) > 1) error("Can't reverse path with multiple destination nodes"); struct path *r = path_create(); r->in = p->out; /* Swap in/out */ r->out = p->in; list_push(&r->destinations, r->out); r->in->refcnt++; r->out->refcnt++; r->in->vt->refcnt++; r->out->vt->refcnt++; list_push(paths, r); } list_push(paths, p); } else { char *buf = path_print(p); warn("Path %s is not enabled", buf); free(buf); path_destroy(p); } return 0; } int config_parse_nodelist(config_setting_t *cfg, struct list *list, struct list *all) { const char *str; struct node *node; switch (config_setting_type(cfg)) { case CONFIG_TYPE_STRING: str = config_setting_get_string(cfg); if (str) { node = list_lookup(all, str); if (node) list_push(list, node); else cerror(cfg, "Unknown outgoing node '%s'", str); } else cerror(cfg, "Invalid outgoing node"); break; case CONFIG_TYPE_ARRAY: for (int i = 0; i < config_setting_length(cfg); i++) { config_setting_t *elm = config_setting_get_elem(cfg, i); str = config_setting_get_string(elm); if (str) { node = list_lookup(all, str); if (node) list_push(list, node); else cerror(elm, "Unknown outgoing node '%s'", str); } else cerror(cfg, "Invalid outgoing node"); } break; default: cerror(cfg, "Invalid output node(s)"); } return 0; } int config_parse_hooklist(config_setting_t *cfg, struct list *list) { const char *str; const struct hook *hook; switch (config_setting_type(cfg)) { case CONFIG_TYPE_STRING: str = config_setting_get_string(cfg); if (str) { hook = list_lookup(&hooks, str); if (hook) list_insert(&list[hook->type], hook->priority, hook->callback); else cerror(cfg, "Unknown hook function '%s'", str); } else cerror(cfg, "Invalid hook function"); break; case CONFIG_TYPE_ARRAY: for (int i = 0; itype], hook->priority, hook->callback); else cerror(elm, "Invalid hook function '%s'", str); } else cerror(cfg, "Invalid hook function"); } break; default: cerror(cfg, "Invalid hook functions"); } return 0; } int config_parse_node(config_setting_t *cfg, struct list *nodes, struct settings *set) { const char *type; int ret; struct node *n = node_create(); /* Required settings */ n->cfg = cfg; n->name = config_setting_name(cfg); if (!n->name) cerror(cfg, "Missing node name"); if (!config_setting_lookup_string(cfg, "type", &type)) cerror(cfg, "Missing node type"); if (!config_setting_lookup_int(cfg, "combine", &n->combine)) n->combine = 1; if (!config_setting_lookup_int(cfg, "affinity", &n->combine)) n->affinity = set->affinity; n->vt = list_lookup(&node_types, type); if (!n->vt) cerror(cfg, "Invalid type for node '%s'", n->name); ret = n->vt->parse(cfg, n); if (!ret) list_push(nodes, n); return ret; }