2014-06-05 09:34:32 +00:00
|
|
|
/**
|
|
|
|
* Configuration parser
|
|
|
|
*
|
2014-06-05 09:35:41 +00:00
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2014-06-05 09:34:32 +00:00
|
|
|
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
|
|
|
|
*/
|
|
|
|
|
2014-06-10 19:44:21 +00:00
|
|
|
#include <stdlib.h>
|
2014-06-05 09:34:50 +00:00
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2014-06-10 19:44:21 +00:00
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
#include "if.h"
|
2014-06-05 09:34:50 +00:00
|
|
|
#include "cfg.h"
|
2014-06-05 09:35:23 +00:00
|
|
|
#include "node.h"
|
|
|
|
#include "path.h"
|
2014-06-05 09:34:32 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
int config_parse(const char *filename, config_t *cfg,
|
2014-06-25 01:53:32 +00:00
|
|
|
struct settings *set, struct node **nodes, struct path **paths)
|
2014-06-05 09:34:32 +00:00
|
|
|
{
|
2014-06-10 16:57:40 +00:00
|
|
|
if (!config_read_file(cfg, filename)) {
|
2014-06-05 09:34:50 +00:00
|
|
|
error("Failed to parse configuration: %s in %s:%d",
|
|
|
|
config_error_text(cfg),
|
|
|
|
config_error_file(cfg),
|
|
|
|
config_error_line(cfg)
|
|
|
|
);
|
2014-06-05 09:34:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:47:22 +00:00
|
|
|
/* Get and check config sections */
|
2014-06-10 16:57:40 +00:00
|
|
|
config_setting_t *cfg_root = config_root_setting(cfg);
|
|
|
|
if (!cfg_root || !config_setting_is_group(cfg_root))
|
2014-06-10 18:47:22 +00:00
|
|
|
error("Missing global section in config file: %s", filename);
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-10 16:57:40 +00:00
|
|
|
config_setting_t *cfg_nodes = config_setting_get_member(cfg_root, "nodes");
|
2014-06-05 09:34:50 +00:00
|
|
|
if (!cfg_nodes || !config_setting_is_group(cfg_nodes))
|
2014-06-10 18:47:22 +00:00
|
|
|
error("Missing node section in config file: %s", filename);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-10 16:57:40 +00:00
|
|
|
config_setting_t *cfg_paths = config_setting_get_member(cfg_root, "paths");
|
2014-06-05 09:34:50 +00:00
|
|
|
if (!cfg_paths || !config_setting_is_list(cfg_paths))
|
2014-06-10 18:47:22 +00:00
|
|
|
error("Missing path section in config file: %s", filename);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
/* Parse global settings */
|
2014-06-25 01:53:32 +00:00
|
|
|
config_parse_global(cfg_root, set);
|
2014-06-10 16:57:40 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
/* Parse nodes */
|
|
|
|
for (int i = 0; i < config_setting_length(cfg_nodes); i++) {
|
|
|
|
config_setting_t *cfg_node = config_setting_get_elem(cfg_nodes, i);
|
2014-06-25 01:53:32 +00:00
|
|
|
config_parse_node(cfg_node, nodes);
|
2014-06-05 09:34:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-05 09:34:50 +00:00
|
|
|
/* Parse paths */
|
2014-06-10 18:47:25 +00:00
|
|
|
for (int i = 0; i < config_setting_length(cfg_paths); i++) {
|
|
|
|
config_setting_t *cfg_path = config_setting_get_elem(cfg_paths, i);
|
2014-06-25 01:53:32 +00:00
|
|
|
config_parse_path(cfg_path, paths, *nodes);
|
2014-06-05 09:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CONFIG_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
int config_parse_global(config_setting_t *cfg, struct settings *set)
|
2014-06-05 09:34:32 +00:00
|
|
|
{
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "name", &set->name))
|
|
|
|
cerror(cfg, "Missing node name");
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
config_setting_lookup_int(cfg, "affinity", &set->affinity);
|
|
|
|
config_setting_lookup_int(cfg, "priority", &set->priority);
|
|
|
|
config_setting_lookup_int(cfg, "protocol", &set->protocol);
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-10 19:44:21 +00:00
|
|
|
const char *user = NULL;
|
|
|
|
const char *group = NULL;
|
|
|
|
|
|
|
|
config_setting_lookup_string(cfg, "user", &user);
|
|
|
|
config_setting_lookup_string(cfg, "group", &group);
|
|
|
|
|
|
|
|
/* Lookup uid and gid */
|
|
|
|
if (user) {
|
|
|
|
struct passwd *pw = getpwnam(user);
|
|
|
|
if (!pw)
|
|
|
|
error("Unknown username: '%s'", user);
|
|
|
|
|
|
|
|
set->uid = pw->pw_uid;
|
|
|
|
set->gid = pw->pw_gid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group) {
|
|
|
|
struct group *gr = getgrnam(group);
|
|
|
|
if (!gr)
|
|
|
|
error("Unknown group: '%s'", group);
|
|
|
|
|
|
|
|
set->gid = gr->gr_gid;
|
|
|
|
}
|
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
set->cfg = cfg;
|
2014-06-05 09:35:41 +00:00
|
|
|
|
2014-06-05 09:34:32 +00:00
|
|
|
return CONFIG_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
int config_parse_path(config_setting_t *cfg,
|
2014-06-25 01:53:32 +00:00
|
|
|
struct path **paths, struct node *nodes)
|
2014-06-05 09:34:32 +00:00
|
|
|
{
|
2014-06-05 09:34:50 +00:00
|
|
|
const char *in_str = NULL;
|
|
|
|
const char *out_str = NULL;
|
|
|
|
int enabled = 1;
|
|
|
|
int reverse = 0;
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-05 09:34:50 +00:00
|
|
|
/* Optional settings */
|
2014-06-10 18:47:25 +00:00
|
|
|
config_setting_lookup_bool(cfg, "enabled", &enabled);
|
|
|
|
config_setting_lookup_bool(cfg, "reverse", &reverse);
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
struct path *path = (struct path *) malloc(sizeof(struct path));
|
|
|
|
if (!path)
|
|
|
|
error("Failed to allocate memory for path");
|
|
|
|
else
|
|
|
|
memset(path, 0, sizeof(struct path));
|
|
|
|
|
2014-06-05 09:34:50 +00:00
|
|
|
/* Required settings */
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "in", &in_str))
|
|
|
|
cerror(cfg, "Missing input node for path");
|
2014-06-05 09:34:32 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "out", &out_str))
|
|
|
|
cerror(cfg, "Missing output node for path");
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
path->in = node_lookup_name(in_str, nodes);
|
|
|
|
if (!path->in)
|
2014-06-10 18:47:25 +00:00
|
|
|
cerror(cfg, "Invalid input node '%s'");
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
path->out = node_lookup_name(out_str, nodes);
|
|
|
|
if (!path->out)
|
2014-06-10 18:47:25 +00:00
|
|
|
cerror(cfg, "Invalid output node '%s'", out_str);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
path->cfg = cfg;
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:44 +00:00
|
|
|
debug(3, "Loaded path from '%s' to '%s'", path->in->name, path->out->name);
|
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
if (enabled) {
|
2014-06-25 01:53:32 +00:00
|
|
|
list_add(*paths, path);
|
|
|
|
|
|
|
|
if (reverse) {
|
2014-06-25 01:53:35 +00:00
|
|
|
struct path *path_rev = (struct path *) malloc(sizeof(struct path));
|
|
|
|
if (!path_rev)
|
2014-06-25 01:53:32 +00:00
|
|
|
error("Failed to allocate memory for path");
|
2014-06-25 01:53:35 +00:00
|
|
|
else
|
|
|
|
memcpy(path_rev, path, sizeof(struct path));
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
path_rev->in = path->out; /* Swap in/out */
|
|
|
|
path_rev->out = path->in;
|
|
|
|
|
|
|
|
list_add(*paths, path_rev);
|
2014-06-25 01:53:32 +00:00
|
|
|
}
|
2014-06-05 09:34:50 +00:00
|
|
|
}
|
2014-06-25 01:53:35 +00:00
|
|
|
else {
|
|
|
|
free(path);
|
2014-06-05 09:34:50 +00:00
|
|
|
warn(" Path is not enabled");
|
2014-06-25 01:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2014-06-05 09:34:50 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 01:53:32 +00:00
|
|
|
int config_parse_node(config_setting_t *cfg, struct node **nodes)
|
2014-06-05 09:34:50 +00:00
|
|
|
{
|
|
|
|
const char *type_str = NULL;
|
|
|
|
const char *remote_str = NULL;
|
|
|
|
const char *local_str = NULL;
|
|
|
|
|
2014-06-25 01:53:32 +00:00
|
|
|
struct node *node;
|
2014-06-25 01:53:35 +00:00
|
|
|
|
|
|
|
/* Allocate memory */
|
|
|
|
node = (struct node *) malloc(sizeof(struct node));
|
|
|
|
if (!node)
|
|
|
|
error("Failed to allocate memory for node");
|
|
|
|
else
|
|
|
|
memset(node, 0, sizeof(struct node));
|
2014-06-05 09:34:50 +00:00
|
|
|
|
|
|
|
/* Required settings */
|
2014-06-25 01:53:35 +00:00
|
|
|
node->name = config_setting_name(cfg);
|
|
|
|
if (!node->name)
|
2014-06-10 18:47:25 +00:00
|
|
|
cerror(cfg, "Missing node name");
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
if (!config_setting_lookup_int(cfg, "id", &node->id))
|
|
|
|
cerror(cfg, "Missing id for node '%s'", node->name);
|
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "type", &type_str))
|
2014-06-25 01:53:35 +00:00
|
|
|
cerror(cfg, "Missing type for node '%s'", node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "remote", &remote_str))
|
2014-06-25 01:53:35 +00:00
|
|
|
cerror(cfg, "Missing remote address for node '%s'", node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-10 18:47:25 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "local", &local_str))
|
2014-06-25 01:53:35 +00:00
|
|
|
cerror(cfg, "Missing local address for node '%s'", node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
node->type = node_lookup_type(type_str);
|
|
|
|
if (node->type == NODE_INVALID)
|
|
|
|
cerror(cfg, "Invalid type '%s' for node '%s'", type_str, node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:42 +00:00
|
|
|
if (resolve_addr(local_str, &node->local, AI_PASSIVE))
|
2014-06-25 01:53:35 +00:00
|
|
|
cerror(cfg, "Failed to resolve local address '%s' of node '%s'", local_str, node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
if (resolve_addr(remote_str, &node->remote, 0))
|
|
|
|
cerror(cfg, "Failed to resolve remote address '%s' of node '%s'", remote_str, node->name);
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
if (!config_setting_lookup_string(cfg, "interface", &node->ifname)) {
|
|
|
|
node->ifname = if_addrtoname((struct sockaddr*) &node->local);
|
|
|
|
}
|
2014-06-25 01:53:32 +00:00
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
node->cfg = cfg;
|
|
|
|
node->ifindex = if_nametoindex(node->ifname);
|
|
|
|
node->mark = node->ifindex + 8000;
|
2014-06-05 09:34:50 +00:00
|
|
|
|
2014-06-25 01:53:32 +00:00
|
|
|
list_add(*nodes, node);
|
|
|
|
|
2014-06-25 01:53:35 +00:00
|
|
|
debug(3, "Loaded %s node '%s'", type_str, node->name);
|
|
|
|
|
|
|
|
return 0;
|
2014-06-05 09:34:32 +00:00
|
|
|
}
|