diff --git a/include/villas/config_helper.h b/include/villas/config_helper.h index 423ac7dcb..6be9afe4b 100644 --- a/include/villas/config_helper.h +++ b/include/villas/config_helper.h @@ -33,5 +33,12 @@ json_t * config_to_json(config_setting_t *cfg); /* Convert a jansson object into a libconfig object. */ int json_to_config(json_t *json, config_setting_t *parent); -/* Create a libconfig object from command line parameters. */ -int config_read_cli(config_t *cfg, int argc, char *argv[]); +/* Create a JSON object from command line parameters. */ +json_t * json_load_cli(int argc, char *argv[]); + +int json_object_extend_str(json_t *orig, const char *str); + +void json_object_extend_key_value(json_t *obj, const char *key, const char *value); + +/* Merge two JSON objects recursively. */ +int json_object_extend(json_t *orig, json_t *merge); diff --git a/include/villas/fpga/card.h b/include/villas/fpga/card.h index 883e875b0..5ca255501 100644 --- a/include/villas/fpga/card.h +++ b/include/villas/fpga/card.h @@ -29,8 +29,6 @@ #pragma once -#include - #include "common.h" #include "kernel/pci.h" #include "kernel/vfio.h" @@ -70,9 +68,9 @@ struct fpga_card { int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc); /** Parse configuration of FPGA card including IP cores from config. */ -int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg); +int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name); -int fpga_card_parse_list(struct list *l, config_setting_t *cfg); +int fpga_card_parse_list(struct list *l, json_t *cfg); /** Check if the FPGA card configuration is plausible. */ int fpga_card_check(struct fpga_card *c); diff --git a/include/villas/fpga/ip.h b/include/villas/fpga/ip.h index a4645bcbe..918173114 100644 --- a/include/villas/fpga/ip.h +++ b/include/villas/fpga/ip.h @@ -30,7 +30,6 @@ #pragma once #include -#include #include "common.h" @@ -60,7 +59,7 @@ struct fpga_ip_type { enum fpga_ip_types type; int (*init)(struct fpga_ip *c); - int (*parse)(struct fpga_ip *c); + int (*parse)(struct fpga_ip *c, json_t *cfg); int (*check)(struct fpga_ip *c); int (*start)(struct fpga_ip *c); int (*stop)(struct fpga_ip *c); @@ -93,7 +92,7 @@ struct fpga_ip { int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt); /** Parse IP core configuration from configuration file */ -int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg); +int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name); /** Check configuration of IP core. */ int fpga_ip_check(struct fpga_ip *c); diff --git a/include/villas/fpga/ips/dft.h b/include/villas/fpga/ips/dft.h index 046082f4f..03c08dbdf 100644 --- a/include/villas/fpga/ips/dft.h +++ b/include/villas/fpga/ips/dft.h @@ -25,7 +25,7 @@ struct dft { int decimation; }; -int dft_parse(struct fpga_ip *c); +int dft_parse(struct fpga_ip *c, json_t *cfg); int dft_start(struct fpga_ip *c); diff --git a/include/villas/fpga/ips/model.h b/include/villas/fpga/ips/model.h index 63b91af21..dadefe4fd 100644 --- a/include/villas/fpga/ips/model.h +++ b/include/villas/fpga/ips/model.h @@ -33,20 +33,20 @@ enum model_xsg_block_type { XSG_BLOCK_INFO = 0x2000 }; -enum model_param_type { - MODEL_PARAM_TYPE_UFIX, - MODEL_PARAM_TYPE_FIX, - MODEL_PARAM_TYPE_FLOAT, - MODEL_PARAM_TYPE_BOOLEAN +enum model_parameter_type { + MODEL_PARAMETER_TYPE_UFIX, + MODEL_PARAMETER_TYPE_FIX, + MODEL_PARAMETER_TYPE_FLOAT, + MODEL_PARAMETER_TYPE_BOOLEAN }; -enum model_param_direction { - MODEL_PARAM_IN, - MODEL_PARAM_OUT, - MODEL_PARAM_INOUT +enum model_parameter_direction { + MODEL_PARAMETER_IN, + MODEL_PARAMETER_OUT, + MODEL_PARAMETER_INOUT }; -union model_param_value { +union model_parameter_value { uint32_t ufix; int32_t fix; float flt; @@ -75,16 +75,16 @@ struct model_info { char *value; }; -struct model_param { +struct model_parameter { char *name; /**< Name of the parameter */ - enum model_param_direction direction; /**< Read / Write / Read-write? */ - enum model_param_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */ + enum model_parameter_direction direction; /**< Read / Write / Read-write? */ + enum model_parameter_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */ int binpt; /**< Binary point for type == MODEL_GW_TYPE_(U)FIX */ uintptr_t offset; /**< Register offset to model::baseaddress */ - union model_param_value default_value; + union model_parameter_value default_value; struct fpga_ip *ip; /**< A pointer to the model structure to which this parameters belongs to. */ }; @@ -93,7 +93,7 @@ struct model_param { int model_init(struct fpga_ip *c); /** Parse model */ -int model_parse(struct fpga_ip *c); +int model_parse(struct fpga_ip *c, json_t *cfg); /** Destroy a model */ int model_destroy(struct fpga_ip *c); @@ -102,17 +102,17 @@ int model_destroy(struct fpga_ip *c); void model_dump(struct fpga_ip *c); /** Add a new parameter to the model */ -void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type); +void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type); /** Remove an existing parameter by its name */ -int model_param_remove(struct fpga_ip *c, const char *name); +int model_parameter_remove(struct fpga_ip *c, const char *name); /** Read a model parameter. * * Note: the data type of the register is taken into account. * All datatypes are converted to double. */ -int model_param_read(struct model_param *p, double *v); +int model_parameter_read(struct model_parameter *p, double *v); /** Update a model parameter. * @@ -120,8 +120,8 @@ int model_param_read(struct model_param *p, double *v); * The double argument will be converted to the respective data type of the * GatewayIn/Out block. */ -int model_param_write(struct model_param *p, double v); +int model_parameter_write(struct model_parameter *p, double v); -int model_param_update(struct model_param *p, struct model_param *u); +int model_parameter_update(struct model_parameter *p, struct model_parameter *u); /** @} */ diff --git a/include/villas/fpga/ips/switch.h b/include/villas/fpga/ips/switch.h index 9c46c2dcb..19b8b5417 100644 --- a/include/villas/fpga/ips/switch.h +++ b/include/villas/fpga/ips/switch.h @@ -13,6 +13,7 @@ #pragma once +#include #include #include "list.h" @@ -41,7 +42,7 @@ int switch_init_paths(struct fpga_ip *c); int switch_destroy(struct fpga_ip *c); -int switch_parse(struct fpga_ip *c); +int switch_parse(struct fpga_ip *c, json_t *cfg); int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si); diff --git a/include/villas/hist.h b/include/villas/hist.h index b3fcd3a6e..567472dac 100644 --- a/include/villas/hist.h +++ b/include/villas/hist.h @@ -93,12 +93,8 @@ char * hist_dump(struct hist *h); /** Prints Matlab struct containing all infos to file. */ int hist_dump_matlab(struct hist *h, FILE *f); -#ifdef WITH_JSON - /** Write the histogram in JSON format to fiel \p f. */ int hist_dump_json(struct hist *h, FILE *f); /** Build a libjansson / JSON object of the histogram. */ json_t * hist_json(struct hist *h); - -#endif /* WITH_JSON */ diff --git a/include/villas/hook.h b/include/villas/hook.h index b73a0c49a..ac938847e 100644 --- a/include/villas/hook.h +++ b/include/villas/hook.h @@ -52,21 +52,13 @@ struct hook { void *_vd; /**< Private data for this hook. This pointer can be used to pass data between consecutive calls of the callback. */ int priority; /**< A priority to change the order of execution within one type of hook. */ + + json_t *cfg; /**< A JSON object containing the configuration of the hook. */ }; -/** Save references to global nodes, paths and settings */ int hook_init(struct hook *h, struct hook_type *vt, struct path *p); -/** Parse a single hook. - * - * A hook definition is composed of the hook name and optional parameters - * seperated by a colon. - * - * Examples: - * "print:stdout" - */ -int hook_parse(struct hook *h, config_setting_t *cfg); - +int hook_parse(struct hook *h, json_t *cfg); int hook_parse_cli(struct hook *h, int argc, char *argv[]); int hook_destroy(struct hook *h); @@ -100,4 +92,4 @@ int hook_cmp_priority(const void *a, const void *b); * hooks = [ "print" ] * } */ -int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *p); +int hook_parse_list(struct list *list, json_t *cfg, struct path *p); diff --git a/include/villas/hook_type.h b/include/villas/hook_type.h index a6c45ece1..400e42b50 100644 --- a/include/villas/hook_type.h +++ b/include/villas/hook_type.h @@ -37,7 +37,7 @@ #include #include -#include +#include /* Forward declarations */ struct hook; @@ -49,7 +49,7 @@ struct hook_type { size_t size; /**< Size of allocation for struct hook::_vd */ - int (*parse)(struct hook *h, config_setting_t *cfg); + int (*parse)(struct hook *h, json_t *cfg); int (*parse_cli)(struct hook *h, int argc, char *argv[]); int (*init)(struct hook *h); /**< Called before path is started to parseHOOK_DESTROYs. */ diff --git a/include/villas/kernel/tc.h b/include/villas/kernel/tc.h index 0a861a8e1..da3cd712c 100644 --- a/include/villas/kernel/tc.h +++ b/include/villas/kernel/tc.h @@ -35,7 +35,7 @@ #include #include -#include +#include typedef uint32_t tc_hdl_t; @@ -43,12 +43,12 @@ struct interface; /** Parse network emulator (netem) settings. * - * @param cfg A libconfig object containing the settings. + * @param cfg A jansson object containing the settings. * @param[out] ne A pointer to a libnl3 qdisc object where setting will be written to. * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ -int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **ne); +int tc_parse(struct rtnl_qdisc **ne, json_t *cfg); /** Print network emulator (netem) setting into buffer. * diff --git a/include/villas/log_config.h b/include/villas/log_config.h index 7e898f82b..86c2281ba 100644 --- a/include/villas/log_config.h +++ b/include/villas/log_config.h @@ -1,4 +1,4 @@ -/** Logging routines that depend on libconfig. +/** Logging routines that depend on jansson. * * @file * @author Steffen Vogel @@ -25,14 +25,13 @@ struct log; -#include +#include #include "log.h" /** Parse logging configuration. */ -int log_parse(struct log *l, config_setting_t *cfg); +int log_parse(struct log *l, json_t *cfg); /** Print configuration error and exit. */ -void cerror(config_setting_t *cfg, const char *fmt, ...) +void jerror(json_error_t *err, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); - diff --git a/include/villas/mapping.h b/include/villas/mapping.h index 346c6f4ce..a814f0b93 100644 --- a/include/villas/mapping.h +++ b/include/villas/mapping.h @@ -23,7 +23,7 @@ #pragma once -#include +#include #include "stats.h" #include "common.h" @@ -87,7 +87,7 @@ struct mapping { int mapping_init(struct mapping *m); -int mapping_parse(struct mapping *m, config_setting_t *cfg); +int mapping_parse(struct mapping *m, json_t *cfg); int mapping_check(struct mapping *m); @@ -95,6 +95,6 @@ int mapping_destroy(struct mapping *m); int mapping_remap(struct mapping *m, struct sample *orig, struct sample *remapped, struct stats *s); -int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg); +int mapping_entry_parse(struct mapping_entry *e, json_t *cfg); int mapping_entry_parse_str(struct mapping_entry *e, const char *str); diff --git a/include/villas/node.h b/include/villas/node.h index 650fe2551..b32142f8b 100644 --- a/include/villas/node.h +++ b/include/villas/node.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include "node_type.h" #include "sample.h" @@ -58,17 +58,19 @@ struct node struct node_type *_vt; /**< Virtual functions (C++ OOP style) */ void *_vd; /**< Virtual data (used by struct node::_vt functions) */ + + json_t *cfg; /**< A JSON object containing the configuration of the node. */ }; int node_init(struct node *n, struct node_type *vt); /** Parse settings of a node. * - * @param cfg A libconfig object pointing to the node. + * @param cfg A JSON object containing the configuration of the node. * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ -int node_parse(struct node *n, config_setting_t *cfg); +int node_parse(struct node *n, json_t *cfg, const char *name); /** Parse settings of a node from cmdline. */ int node_parse_cli(struct node *n, int argc, char *argv[]); @@ -128,10 +130,10 @@ int node_write(struct node *n, struct sample *smps[], unsigned cnt); * out = [ "sintef", "scedu" ] * out = "acs" * - * @param cfg The libconfig object handle for "out". + * @param cfg A JSON array or string. See examples above. * @param nodes The nodes will be added to this list. * @param all This list contains all valid nodes. */ -int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all); +int node_parse_list(struct list *list, json_t *cfg, struct list *all); /** @} */ diff --git a/include/villas/node_type.h b/include/villas/node_type.h index 9b8ca66c3..3b00957a3 100644 --- a/include/villas/node_type.h +++ b/include/villas/node_type.h @@ -26,7 +26,7 @@ #pragma once -#include +#include #include "list.h" #include "common.h" @@ -78,11 +78,11 @@ struct node_type { /** Parse node connection details. * * @param n A pointer to the node object. - * @param cfg A libconfig object pointing to the node. + * @param cfg A JSON object containing the configuration of the node. * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ - int (*parse)(struct node *n, config_setting_t *cfg); + int (*parse)(struct node *n, json_t *cfg); /** Parse node from command line arguments. */ int (*parse_cli)(struct node *n, int argc, char *argv[]); @@ -118,10 +118,10 @@ struct node_type { * Indexes used to address @p m will wrap around after len messages. * Some node-types might only support to receive one message at a time. * - * @param n A pointer to the node object. - * @param smps An array of pointers to memory blocks where the function should store received samples. - * @param cnt The number of messages which should be received. - * @return The number of messages actually received. + * @param n A pointer to the node object. + * @param smps An array of pointers to memory blocks where the function should store received samples. + * @param cnt The number of messages which should be received. + * @return The number of messages actually received. */ int (*read) (struct node *n, struct sample *smps[], unsigned cnt); @@ -132,10 +132,10 @@ struct node_type { * The messages have to be stored in a circular buffer / array m. * So the indexes will wrap around after len. * - * @param n A pointer to the node object. - * @param smps An array of pointers to memory blocks where samples read from. - * @param cnt The number of messages which should be sent. - * @return The number of messages actually sent. + * @param n A pointer to the node object. + * @param smps An array of pointers to memory blocks where samples read from. + * @param cnt The number of messages which should be sent. + * @return The number of messages actually sent. */ int (*write)(struct node *n, struct sample *smps[], unsigned cnt); @@ -143,7 +143,7 @@ struct node_type { * * This is not supported by all node-types! * - * @param n A pointer to the node object. + * @param n A pointer to the node object. */ int (*reverse)(struct node *n); }; diff --git a/include/villas/nodes/file.h b/include/villas/nodes/file.h index 78ab29c0c..50e5667fd 100644 --- a/include/villas/nodes/file.h +++ b/include/villas/nodes/file.h @@ -46,7 +46,7 @@ struct file { AFILE *handle; /**< libc: stdio file handle. */ const char *mode; /**< libc: fopen() mode. */ - const char *fmt; /**< Format string for file name. */ + const char *format; /**< Format string for file name. */ char *uri; /**< Real file name. */ } read, write; @@ -78,7 +78,7 @@ struct file { char * file_print(struct node *n); /** @see node_type::parse */ -int file_parse(struct node *n, config_setting_t *cfg); +int file_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int file_start(struct node *n); diff --git a/include/villas/nodes/fpga.h b/include/villas/nodes/fpga.h index ece227bf5..fe235bb3b 100644 --- a/include/villas/nodes/fpga.h +++ b/include/villas/nodes/fpga.h @@ -44,7 +44,7 @@ int fpga_init(struct super_node *sn); int fpga_deinit(); /** @see node_type::parse */ -int fpga_parse(struct node *n, config_setting_t *cfg); +int fpga_parse(struct node *n, json_t *cfg); struct fpga_card * fpga_lookup_card(const char *name); diff --git a/include/villas/nodes/loopback.h b/include/villas/nodes/loopback.h index e92e8fe39..f11d82446 100644 --- a/include/villas/nodes/loopback.h +++ b/include/villas/nodes/loopback.h @@ -29,8 +29,6 @@ #pragma once -#include - #include "queue_signalled.h" #include "pool.h" @@ -53,7 +51,7 @@ struct loopback { char * loopback_print(struct node *n); /** @see node_type::parse */ -int loopback_parse(struct node *n, config_setting_t *cfg); +int loopback_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int loopback_open(struct node *n); diff --git a/include/villas/nodes/nanomsg.h b/include/villas/nodes/nanomsg.h index 18109487d..0d3818c65 100644 --- a/include/villas/nodes/nanomsg.h +++ b/include/villas/nodes/nanomsg.h @@ -50,7 +50,7 @@ struct nanomsg { char * nanomsg_print(struct node *n); /** @see node_type::parse */ -int nanomsg_parse(struct node *n, config_setting_t *cfg); +int nanomsg_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int nanomsg_start(struct node *n); diff --git a/include/villas/nodes/ngsi.h b/include/villas/nodes/ngsi.h index 9794b1a47..bd9c4a82d 100644 --- a/include/villas/nodes/ngsi.h +++ b/include/villas/nodes/ngsi.h @@ -39,7 +39,6 @@ #include #include "list.h" -#include "msg.h" #include "super_node.h" #include "node.h" @@ -77,7 +76,7 @@ int ngsi_init(struct super_node *sn); int ngsi_deinit(); /** @see node_type::parse */ -int ngsi_parse(struct node *n, config_setting_t *cfg); +int ngsi_parse(struct node *n, json_t *cfg); /** @see node_type::print */ char * ngsi_print(struct node *n); diff --git a/include/villas/nodes/opal.h b/include/villas/nodes/opal.h index 663a71631..61fc4f6db 100644 --- a/include/villas/nodes/opal.h +++ b/include/villas/nodes/opal.h @@ -67,7 +67,7 @@ int opal_init(struct super_node *sn); int opal_deinit(); /** @see node_type::parse */ -int opal_parse(struct node *n, config_setting_t *cfg); +int opal_parse(struct node *n, json_t *cfg); /** @see node_type::print */ char * opal_print(struct node *n); diff --git a/include/villas/nodes/shmem.h b/include/villas/nodes/shmem.h index c001d1d22..5af608e86 100644 --- a/include/villas/nodes/shmem.h +++ b/include/villas/nodes/shmem.h @@ -51,7 +51,7 @@ struct shmem { char * shmem_print(struct node *n); /** @see node_type::parse */ -int shmem_parse(struct node *n, config_setting_t *cfg); +int shmem_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int shmem_open(struct node *n); diff --git a/include/villas/nodes/signal.h b/include/villas/nodes/signal.h index ed47edf04..106b52a43 100644 --- a/include/villas/nodes/signal.h +++ b/include/villas/nodes/signal.h @@ -29,8 +29,6 @@ #pragma once -#include - #include "timing.h" /* Forward declarations */ @@ -71,7 +69,7 @@ struct signal { char * signal_print(struct node *n); /** @see node_type::parse */ -int signal_parse(struct node *n, config_setting_t *cfg); +int signal_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int signal_open(struct node *n); diff --git a/include/villas/nodes/socket.h b/include/villas/nodes/socket.h index bf0700d90..769741155 100644 --- a/include/villas/nodes/socket.h +++ b/include/villas/nodes/socket.h @@ -112,7 +112,7 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt); int socket_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::parse */ -int socket_parse(struct node *n, config_setting_t *cfg); +int socket_parse(struct node *n, json_t *cfg); /** @see node_type::print */ char * socket_print(struct node *n); diff --git a/include/villas/nodes/test_rtt.h b/include/villas/nodes/test_rtt.h index db7469241..d8cb5d7a6 100644 --- a/include/villas/nodes/test_rtt.h +++ b/include/villas/nodes/test_rtt.h @@ -55,7 +55,7 @@ struct test_rtt { char * test_rtt_print(struct node *n); /** @see node_type::parse */ -int test_rtt_parse(struct node *n, config_setting_t *cfg); +int test_rtt_parse(struct node *n, json_t *cfg); /** @see node_type::open */ int test_rtt_start(struct node *n); diff --git a/include/villas/nodes/zeromq.h b/include/villas/nodes/zeromq.h index 88841e3d9..ca9d264c0 100644 --- a/include/villas/nodes/zeromq.h +++ b/include/villas/nodes/zeromq.h @@ -74,7 +74,7 @@ struct zeromq { char * zeromq_print(struct node *n); /** @see node_type::parse */ -int zeromq_parse(struct node *n, config_setting_t *cfg); +int zeromq_parse(struct node *n, json_t *cfg); /** @see node_type::init */ int zeromq_init(); diff --git a/include/villas/path.h b/include/villas/path.h index d64f6df5b..73f22c542 100644 --- a/include/villas/path.h +++ b/include/villas/path.h @@ -30,7 +30,7 @@ #pragma once #include -#include +#include #include "list.h" #include "queue.h" @@ -83,6 +83,8 @@ struct path struct stats *stats; /**< Statistic counters. This is a pointer to the statistic hooks private data. */ struct super_node *super_node; /**< The super node this path belongs to. */ + + json_t *cfg; /**< A JSON object containing the configuration of the path. */ }; /** Initialize internal data structures. */ @@ -140,12 +142,12 @@ int path_uses_node(struct path *p, struct node *n); /** Parse a single path and add it to the global configuration. * - * @param cfg A libconfig object pointing to the path + * @param cfg A JSON object containing the configuration of the path. * @param p Pointer to the allocated memory for this path * @param nodes A linked list of all existing nodes * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ -int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes); +int path_parse(struct path *p, json_t *cfg, struct list *nodes); /** @} */ diff --git a/include/villas/plugin.h b/include/villas/plugin.h index d4172f15c..1531259ba 100644 --- a/include/villas/plugin.h +++ b/include/villas/plugin.h @@ -94,7 +94,7 @@ int plugin_init(struct plugin *p); int plugin_destroy(struct plugin *p); -int plugin_parse(struct plugin *p, config_setting_t *cfg); +int plugin_parse(struct plugin *p, json_t *cfg); int plugin_load(struct plugin *p); diff --git a/include/villas/stats.h b/include/villas/stats.h index 5ea72ce23..a3c377d63 100644 --- a/include/villas/stats.h +++ b/include/villas/stats.h @@ -25,6 +25,7 @@ #define _STATS_H_ #include +#include #include "hist.h" @@ -73,11 +74,7 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt); int stats_commit(struct stats *s, struct stats_delta *d); -#ifdef WITH_JSON - #include - json_t * stats_json(struct stats *s); -#endif void stats_reset(struct stats *s); diff --git a/include/villas/super_node.h b/include/villas/super_node.h index 1f33dd31a..72a5f9b89 100644 --- a/include/villas/super_node.h +++ b/include/villas/super_node.h @@ -1,8 +1,4 @@ -/** Configuration file parser. - * - * The server program is configured by a single file. - * This config file is parsed with a third-party library: - * libconfig http://www.hyperrealm.com/libconfig/ +/** The super node object holding the state of the application. * * @file * @author Steffen Vogel @@ -27,8 +23,6 @@ #pragma once -#include - #include "list.h" #include "api.h" #include "web.h" @@ -57,8 +51,7 @@ struct super_node { enum state state; - config_t cfg; /**< Pointer to configuration file */ - json_t *json; /**< JSON representation of the same config. */ + json_t *cfg; /**< JSON representation of the configuration. */ }; /* Compatibility with libconfig < 1.5 */ @@ -82,7 +75,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri); * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ -int super_node_parse(struct super_node *sn, config_setting_t *cfg); +int super_node_parse_json(struct super_node *sn, json_t *cfg); /** Check validity of super node configuration. */ int super_node_check(struct super_node *sn); diff --git a/include/villas/web.h b/include/villas/web.h index 3521d5b71..a299146e4 100644 --- a/include/villas/web.h +++ b/include/villas/web.h @@ -23,7 +23,6 @@ #pragma once -#include #include #include "common.h" @@ -60,4 +59,4 @@ int web_start(struct web *w); int web_stop(struct web *w); /** Parse HTTPd and WebSocket related options */ -int web_parse(struct web *w, config_setting_t *lcs); +int web_parse(struct web *w, json_t *cfg); diff --git a/lib/Makefile.villas.inc b/lib/Makefile.villas.inc index bf5f00e05..9d4d00d02 100644 --- a/lib/Makefile.villas.inc +++ b/lib/Makefile.villas.inc @@ -26,7 +26,6 @@ LIB = $(BUILDDIR)/$(LIB_NAME).so.$(LIB_ABI_VERSION) WITH_WEB ?= 1 WITH_API ?= 1 -WITH_JSON ?= 1 # Object files for libvillas LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \ @@ -46,12 +45,6 @@ endif LIB_PKGS += openssl libcurl -ifeq ($(WITH_JSON),1) - LIB_SRCS += lib/formats/json.c - LIB_PKGS += jansson - LIB_CFLAGS += -DWITH_JSON -endif - ifeq ($(WITH_WEB),1) -include lib/web/Makefile.inc endif diff --git a/lib/api/Makefile.inc b/lib/api/Makefile.inc index f83c84d67..a9d0a41c4 100644 --- a/lib/api/Makefile.inc +++ b/lib/api/Makefile.inc @@ -20,10 +20,6 @@ # along with this program. If not, see . ################################################################################### -ifndef WITH_JSON - $(error API support requires JSON) -endif - LIB_SRCS += lib/api.c LIB_SRCS += $(wildcard lib/api/*.c) diff --git a/lib/api/actions/config.c b/lib/api/actions/config.c index db42997d1..709910613 100644 --- a/lib/api/actions/config.c +++ b/lib/api/actions/config.c @@ -20,8 +20,6 @@ * along with this program. If not, see . *********************************************************************************/ -#include - #include "api.h" #include "utils.h" #include "plugin.h" @@ -30,9 +28,7 @@ static int api_config(struct api_action *h, json_t *args, json_t **resp, struct api_session *s) { - config_setting_t *cfg_root = config_root_setting(&s->api->super_node->cfg); - - *resp = cfg_root ? config_to_json(cfg_root) : json_object(); + *resp = s->api->super_node->cfg; return 0; } diff --git a/lib/api/actions/nodes.c b/lib/api/actions/nodes.c index 121dd9dce..0375015b6 100644 --- a/lib/api/actions/nodes.c +++ b/lib/api/actions/nodes.c @@ -47,7 +47,7 @@ static int api_nodes(struct api_action *r, json_t *args, json_t **resp, struct a /* Add all additional fields of node here. * This can be used for metadata */ - json_object_update(json_node, config_to_json(n->cfg)); + json_object_update(json_node, n->cfg); json_array_append_new(json_nodes, json_node); } diff --git a/lib/api/actions/paths.c b/lib/api/actions/paths.c index e89e21ce5..30a47477b 100644 --- a/lib/api/actions/paths.c +++ b/lib/api/actions/paths.c @@ -47,7 +47,7 @@ static int api_paths(struct api_action *r, json_t *args, json_t **resp, struct a /* Add all additional fields of node here. * This can be used for metadata */ - json_object_update(json_path, config_to_json(p->cfg)); + json_object_update(json_path, p->cfg); json_array_append_new(json_paths, json_path); } diff --git a/lib/config_helper.c b/lib/config_helper.c index 2353c2123..5ee6dc735 100644 --- a/lib/config_helper.c +++ b/lib/config_helper.c @@ -20,10 +20,13 @@ * along with this program. If not, see . *********************************************************************************/ +#include + #include "config_helper.h" #include "utils.h" -#ifdef WITH_JSON +#ifdef WITH_LIBCONFIG + static int json_to_config_type(int type) { switch (type) { @@ -139,24 +142,180 @@ int json_to_config(json_t *json, config_setting_t *parent) return 0; } -#endif /* WITH_JSON */ +#endif /* WITH_LIBCONFIG */ -int config_read_cli(config_t *cfg, int argc, char *argv[]) +void json_object_extend_key_value(json_t *obj, const char *key, const char *value) { - int ret; - char *str = NULL; + char *end, *cpy, *key1, *key2; - for (int i = 0; i < argc; i++) - str = strcatf(&str, "%s", argv[i]); + double real; + long integer; - if (!str) - return 0; + json_t *arr, *new, *existing, *subobj; - config_set_auto_convert(cfg, 1); + /* Is the key pointing to an object? */ + subobj = obj; + cpy = strdup(key); - ret = config_read_string(cfg, str); + key1 = strtok(cpy, "."); + key2 = strtok(NULL, "."); - free(str); + while (key1 && key2) { + existing = json_object_get(subobj, key1); + if (existing) + subobj = existing; + else { + new = json_object(); + json_object_set(subobj, key1, new); - return ret != CONFIG_TRUE; + subobj = new; + } + + key1 = key2; + key2 = strtok(NULL, "."); + } + + /* Try to parse as integer */ + integer = strtol(value, &end, 0); + if (*end == 0) { + new = json_integer(integer); + goto success; + } + + /* Try to parse as floating point */ + real = strtod(value, &end); + if (*end == 0) { + new = json_real(real); + goto success; + } + + /* Try to parse special types */ + if (!strcmp(value, "true")) { + new = json_true(); + goto success; + } + + if (!strcmp(value, "false")) { + new = json_false(); + goto success; + } + + if (!strcmp(value, "null")) { + new = json_null(); + goto success; + } + + /* Fallback to string */ + new = json_string(value); + +success: + /* Does the key already exist? + * If yes, transform to array. */ + existing = json_object_get(subobj, key1); + if (existing) { + if (json_is_array(existing)) + arr = existing; + else { + arr = json_array(); + json_object_set(subobj, key1, arr); + json_array_append(arr, existing); + } + + json_array_append(arr, new); + } + else + json_object_set(subobj, key1, new); +} + +json_t * json_load_cli(int argc, char *argv[]) +{ + char *opt; + char *key = NULL; + char *value = NULL; + char *sep, *cpy; + + json_t *json = json_object(); + + for (int i = 1; i < argc; i++) { + opt = argv[i]; + + /* Long Option */ + if (opt[0] == '-' && opt[1] == '-') { + /* Option without value? Abort. */ + if (key != NULL) + return NULL; + + key = opt + 2; + + /* Does this option has the form "--option=value"? */ + sep = strchr(key, '='); + if (sep) { + cpy = strdup(key); + + key = strtok(cpy, "="); + value = strtok(NULL, ""); + + json_object_extend_key_value(json, key, value); + + free(cpy); + key = NULL; + } + } + /* Value */ + else { + /* Value without key. Abort. */ + if (key == NULL) + return NULL; + + value = opt; + + json_object_extend_key_value(json, key, value); + key = NULL; + } + } + + return json; +} + +int json_object_extend(json_t *obj, json_t *merge) +{ + const char *key; + void *tmp; + int ret; + json_t *merge_value, *obj_value; + + if (!json_is_object(obj) || !json_is_object(merge)) + return -1; + + json_object_foreach_safe(merge, tmp, key, merge_value) { + obj_value = json_object_get(obj, key); + if (obj_value && json_is_object(obj_value)) + ret = json_object_extend(obj_value, merge_value); + else + ret = json_object_set(obj, key, merge_value); + + if (ret) + return ret; + } + + return 0; +} + +int json_object_extend_str(json_t *obj, const char *str) +{ + char *key, *value, *cpy; + + cpy = strdup(str); + + key = strtok(cpy, "="); + value = strtok(NULL, ""); + + if (!key || !value) + return -1; + + json_object_extend_key_value(obj, key, value); + + free(cpy); + + return 0; } diff --git a/lib/fpga/card.c b/lib/fpga/card.c index 4f9c3f8ea..d0aa8c566 100644 --- a/lib/fpga/card.c +++ b/lib/fpga/card.c @@ -55,48 +55,59 @@ int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container * return 0; } -int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg) +int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name) { int ret; - const char *slot, *id, *err; - config_setting_t *cfg_ips, *cfg_slot, *cfg_id; - c->name = config_setting_name(cfg); + json_t *cfg_ips; + json_t *cfg_slot = NULL; + json_t *cfg_id = NULL; + json_error_t err; - config_setting_lookup_int(cfg, "affinity", &c->affinity); - config_setting_lookup_bool(cfg, "do_reset", &c->do_reset); + c->name = strdup(name); + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: b, s?: o, s?: o, s: o }" + "affinity", &c->affinity, + "do_reset", &c->do_reset, + "slot", &cfg_slot, + "id", &cfg_id, + "ips", &cfg_ips + ); + if (ret) + jerror(&err, "Failed to parse FPGA vard configuration"); - cfg_slot = config_setting_get_member(cfg, "slot"); if (cfg_slot) { - slot = config_setting_get_string(cfg_slot); + const char *err, *slot; + + slot = json_string_value(cfg_slot); if (slot) { ret = pci_device_parse_slot(&c->filter, slot, &err); if (ret) - cerror(cfg_slot, "Failed to parse PCI slot: %s", err); + error("Failed to parse PCI slot: %s", err); } else - cerror(cfg_slot, "PCI slot must be a string"); + error("PCI slot must be a string"); } - cfg_id = config_setting_get_member(cfg, "id"); if (cfg_id) { - id = config_setting_get_string(cfg_id); + const char *err, *id; + + id = json_string_value(cfg_id); if (id) { ret = pci_device_parse_id(&c->filter, (char*) id, &err); if (ret) - cerror(cfg_id, "Failed to parse PCI id: %s", err); + error("Failed to parse PCI id: %s", err); } else - cerror(cfg_slot, "PCI ID must be a string"); + error("PCI ID must be a string"); } - cfg_ips = config_setting_get_member(cfg, "ips"); - if (!cfg_ips) - cerror(cfg, "FPGA configuration is missing ips section"); - - for (int i = 0; i < config_setting_length(cfg_ips); i++) { - config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i); + if (!json_is_object(cfg_ips)) + error("FPGA card IPs section must be an object"); + const char *name_ip; + json_t *cfg_ip; + json_object_foreach(cfg_ips, name_ip, cfg_ip) { const char *vlnv; struct fpga_ip_type *vt; @@ -104,45 +115,45 @@ int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg) ip->card = c; - if (!config_setting_lookup_string(cfg, "vlnv", &vlnv)) - cerror(cfg, "FPGA IP core %s is missing the VLNV identifier", c->name); + ret = json_unpack_ex(cfg_ip, &err, 0, "{ s: s }", "vlnv", &vlnv); + if (ret) + error("Failed to parse FPGA IP '%s' of card '%s'", name_ip, name); vt = fpga_ip_type_lookup(vlnv); if (!vt) - cerror(cfg, "FPGA IP core VLNV identifier '%s' is invalid", vlnv); + error("FPGA IP core VLNV identifier '%s' is invalid", vlnv); ret = fpga_ip_init(ip, vt); if (ret) error("Failed to initalize FPGA IP core"); - ret = fpga_ip_parse(ip, cfg_ip); + ret = fpga_ip_parse(ip, cfg_ip, name_ip); if (ret) - cerror(cfg_ip, "Failed to parse FPGA IP core"); + error("Failed to parse FPGA IP core"); list_push(&c->ips, ip); } - c->cfg = cfg; c->state = STATE_PARSED; return 0; } -int fpga_card_parse_list(struct list *cards, config_setting_t *cfg) +int fpga_card_parse_list(struct list *cards, json_t *cfg) { int ret; - if (!config_setting_is_group(cfg)) - cerror(cfg, "FPGA configuration section must be a group"); - - for (int i = 0; i < config_setting_length(cfg); i++) { - config_setting_t *cfg_fpga = config_setting_get_elem(cfg, i); + if (!json_is_object(cfg)) + error("FPGA card configuration section must be a JSON object"); + const char *name; + json_t *cfg_fpga; + json_object_foreach(cfg, name, cfg_fpga) { struct fpga_card *c = alloc(sizeof(struct fpga_card)); - ret = fpga_card_parse(c, cfg_fpga); + ret = fpga_card_parse(c, cfg_fpga, name); if (ret) - cerror(cfg_fpga, "Failed to parse FPGA card configuration"); + error("Failed to parse FPGA card configuration"); list_push(cards, c); } diff --git a/lib/fpga/ip.c b/lib/fpga/ip.c index b407d6c36..de83738ef 100644 --- a/lib/fpga/ip.c +++ b/lib/fpga/ip.c @@ -20,8 +20,6 @@ * along with this program. If not, see . *********************************************************************************/ -#include - #include "log_config.h" #include "log.h" #include "plugin.h" @@ -46,34 +44,33 @@ int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt) return ret; } -int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg) +int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name) { - int ret; - long long baseaddr; + int ret, baseaddr = -1; assert(c->state != STATE_STARTED && c->state != STATE_DESTROYED); - c->cfg = cfg; + c->name = strdup(name); + c->baseaddr = -1; + c->irq = -1; + c->port = -1; - c->name = config_setting_name(cfg); - if (!c->name) - cerror(cfg, "IP is missing a name"); + json_error_t err; - /* Common settings */ - if (config_setting_lookup_int64(cfg, "baseaddr", &baseaddr)) - c->baseaddr = baseaddr; - else - c->baseaddr = -1; + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i, s?: i }", + "baseaddr", &baseaddr, + "irq", &c->irq, + "port", &c->port + ); + if (ret) + jerror(&err, "Failed to parse configuration for FPGA IP '%s'", name); - if (!config_setting_lookup_int(cfg, "irq", &c->irq)) - c->irq = -1; - if (!config_setting_lookup_int(cfg, "port", &c->port)) - c->port = -1; + c->baseaddr = baseaddr; /* Type sepecific settings */ - ret = c->_vt && c->_vt->parse ? c->_vt->parse(c) : 0; + ret = c->_vt && c->_vt->parse ? c->_vt->parse(c, cfg) : 0; if (ret) - error("Failed to parse settings for IP core '%s'", c->name); + error("Failed to parse settings for IP core '%s'", name); c->state = STATE_PARSED; diff --git a/lib/fpga/ips/dft.c b/lib/fpga/ips/dft.c index c3c1ec809..9657287e6 100644 --- a/lib/fpga/ips/dft.c +++ b/lib/fpga/ips/dft.c @@ -13,33 +13,40 @@ #include "fpga/card.h" #include "fpga/ips/dft.h" -int dft_parse(struct fpga_ip *c) +int dft_parse(struct fpga_ip *c, json_t *cfg) { struct dft *dft = c->_vd; - config_setting_t *cfg_harms; + int ret; - if (!config_setting_lookup_int(c->cfg, "period", &dft->period)) - cerror(c->cfg, "DFT IP core requires 'period' setting"); + json_t *cfg_harms; + json_error_t err; - if (!config_setting_lookup_int(c->cfg, "decimation", &dft->decimation)) - cerror(c->cfg, "DFT IP core requires 'decimation' setting"); + ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: o }", + "period", &dft->period, + "decimation", &dft->decimation, + "harmonics", &cfg_harms + ); + if (ret) + jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name); - cfg_harms = config_setting_get_member(c->cfg, "harmonics"); - if (!cfg_harms) - cerror(c->cfg, "DFT IP core requires 'harmonics' setting!"); + if (!json_is_array(cfg_harms)) + error("DFT IP core requires 'harmonics' to be an array of integers!"); - if (!config_setting_is_array(cfg_harms)) - cerror(c->cfg, "DFT IP core requires 'harmonics' to be an array of integers!"); - - dft->num_harmonics = config_setting_length(cfg_harms); + dft->num_harmonics = json_array_size(cfg_harms); if (dft->num_harmonics <= 0) - cerror(cfg_harms, "DFT IP core requires 'harmonics' to contain at least 1 integer!"); + error("DFT IP core requires 'harmonics' to contain at least 1 value!"); dft->fharmonics = alloc(sizeof(float) * dft->num_harmonics); - for (int i = 0; i < dft->num_harmonics; i++) - dft->fharmonics[i] = (float) config_setting_get_int_elem(cfg_harms, i) / dft->period; + size_t index; + json_t *cfg_harm; + json_array_foreach(cfg_harms, index, cfg_harm) { + if (!json_is_real(cfg_harm)) + error("DFT IP core requires all 'harmonics' values to be of floating point type"); + + dft->fharmonics[index] = (float) json_number_value(cfg_harm) / dft->period; + } return 0; } diff --git a/lib/fpga/ips/fifo.c b/lib/fpga/ips/fifo.c index 4ab7a9c5b..efe387e2f 100644 --- a/lib/fpga/ips/fifo.c +++ b/lib/fpga/ips/fifo.c @@ -91,16 +91,21 @@ ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len) return nextlen; } -int fifo_parse(struct fpga_ip *c) +int fifo_parse(struct fpga_ip *c, json_t *cfg) { struct fifo *fifo = c->_vd; - int baseaddr_axi4; + int baseaddr_axi4 = -1, ret; - if (config_setting_lookup_int(c->cfg, "baseaddr_axi4", &baseaddr_axi4)) - fifo->baseaddr_axi4 = baseaddr_axi4; - else - fifo->baseaddr_axi4 = -1; + json_error_t err; + + fifo->baseaddr_axi4 = -1; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }", "baseaddr_axi4", &baseaddr_axi4); + if (ret) + jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name); + + fifo->baseaddr_axi4 = baseaddr_axi4; return 0; } diff --git a/lib/fpga/ips/model.c b/lib/fpga/ips/model.c index a54781904..f8a0cb770 100644 --- a/lib/fpga/ips/model.c +++ b/lib/fpga/ips/model.c @@ -18,7 +18,7 @@ #include "fpga/card.h" #include "fpga/ips/model.h" -static int model_param_destroy(struct model_param *p) +static int model_parameter_destroy(struct model_parameter *p) { free(p->name); @@ -64,7 +64,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter if (length < 4) break; /* block is to small to describe a gateway */ - struct model_param *e, *p = alloc(sizeof(struct model_param)); + struct model_parameter *e, *p = alloc(sizeof(struct model_parameter)); p->name = copy_string(3); p->default_value.flt = *((float *) &data[1]); @@ -75,7 +75,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter e = list_lookup(parameters, p->name); if (e) - model_param_update(e, p); + model_parameter_update(e, p); else list_push(parameters, p); break; @@ -133,28 +133,40 @@ static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr) return i; } -int model_parse(struct fpga_ip *c) +int model_parse(struct fpga_ip *c, json_t *cfg) { struct model *m = c->_vd; - config_setting_t *cfg_params, *cfg_param; + int ret; + + json_t *cfg_params; + json_error_t err; if (strcmp(c->vlnv.library, "hls") == 0) m->type = MODEL_TYPE_HLS; else if (strcmp(c->vlnv.library, "sysgen") == 0) m->type = MODEL_TYPE_XSG; else - cerror(c->cfg, "Invalid model type: %s", c->vlnv.library); + error("Unsupported model type: %s", c->vlnv.library); + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "parameters", &cfg_params); + if (ret) + jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name); - cfg_params = config_setting_get_member(c->cfg, "parameters"); if (cfg_params) { - for (int i = 0; i < config_setting_length(cfg_params); i++) { - cfg_param = config_setting_get_elem(cfg_params, i); + if (!json_is_object(cfg_params)) + error("Setting 'parameters' must be a JSON object"); - struct model_param *p = alloc(sizeof(struct model_param)); + const char *name; + json_t *value; + json_object_foreach(cfg_params, name, value) { + if (!json_is_real(value)) + error("Parameters of FPGA IP '%s' must be of type floating point", c->name); - p->name = config_setting_name(cfg_param); - p->default_value.flt = config_setting_get_float(cfg_param); + struct model_parameter *p = alloc(sizeof(struct model_parameter)); + + p->name = strdup(name); + p->default_value.flt = json_real_value(value); list_push(&m->parameters, p); } @@ -206,12 +218,12 @@ int model_init(struct fpga_ip *c) /* Set default values for parameters */ for (size_t i = 0; i < list_length(&m->parameters); i++) { - struct model_param *p = list_at(&m->parameters, i); + struct model_parameter *p = list_at(&m->parameters, i); p->ip = c; - if (p->direction == MODEL_PARAM_IN) { - model_param_write(p, p->default_value.flt); + if (p->direction == MODEL_PARAMETER_IN) { + model_parameter_write(p, p->default_value.flt); info("Set parameter '%s' updated to default value: %f", p->name, p->default_value.flt); } } @@ -226,7 +238,7 @@ int model_destroy(struct fpga_ip *c) { struct model *m = c->_vd; - list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true); + list_destroy(&m->parameters, (dtor_cb_t) model_parameter_destroy, true); list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true); if (m->xsg.map != NULL) @@ -245,9 +257,9 @@ void model_dump(struct fpga_ip *c) { INDENT info("Parameters:"); for (size_t i = 0; i < list_length(&m->parameters); i++) { INDENT - struct model_param *p = list_at(&m->parameters, i); + struct model_parameter *p = list_at(&m->parameters, i); - if (p->direction == MODEL_PARAM_IN) + if (p->direction == MODEL_PARAMETER_IN) info("%#jx: %s (%s) = %.3f %s %u", p->offset, p->name, @@ -256,7 +268,7 @@ void model_dump(struct fpga_ip *c) param_type[p->type], p->binpt ); - else if (p->direction == MODEL_PARAM_OUT) + else if (p->direction == MODEL_PARAMETER_OUT) info("%#jx: %s (%s)", p->offset, p->name, @@ -273,52 +285,52 @@ void model_dump(struct fpga_ip *c) } } -int model_param_read(struct model_param *p, double *v) +int model_parameter_read(struct model_parameter *p, double *v) { struct fpga_ip *c = p->ip; - union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset); + union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset); switch (p->type) { - case MODEL_PARAM_TYPE_UFIX: + case MODEL_PARAMETER_TYPE_UFIX: *v = (double) ptr->ufix / (1 << p->binpt); break; - case MODEL_PARAM_TYPE_FIX: + case MODEL_PARAMETER_TYPE_FIX: *v = (double) ptr->fix / (1 << p->binpt); break; - case MODEL_PARAM_TYPE_FLOAT: + case MODEL_PARAMETER_TYPE_FLOAT: *v = (double) ptr->flt; break; - case MODEL_PARAM_TYPE_BOOLEAN: + case MODEL_PARAMETER_TYPE_BOOLEAN: *v = (double) ptr->ufix ? 1 : 0; } return 0; } -int model_param_write(struct model_param *p, double v) +int model_parameter_write(struct model_parameter *p, double v) { struct fpga_ip *c = p->ip; - union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset); + union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset); switch (p->type) { - case MODEL_PARAM_TYPE_UFIX: + case MODEL_PARAMETER_TYPE_UFIX: ptr->ufix = (uint32_t) (v * (1 << p->binpt)); break; - case MODEL_PARAM_TYPE_FIX: + case MODEL_PARAMETER_TYPE_FIX: ptr->fix = (int32_t) (v * (1 << p->binpt)); break; - case MODEL_PARAM_TYPE_FLOAT: + case MODEL_PARAMETER_TYPE_FLOAT: ptr->flt = (float) v; break; - case MODEL_PARAM_TYPE_BOOLEAN: + case MODEL_PARAMETER_TYPE_BOOLEAN: ptr->bol = (bool) v; break; } @@ -326,10 +338,10 @@ int model_param_write(struct model_param *p, double v) return 0; } -void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type) +void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type) { struct model *m = c->_vd; - struct model_param *p = alloc(sizeof(struct model_param)); + struct model_parameter *p = alloc(sizeof(struct model_parameter)); p->name = strdup(name); p->type = type; @@ -338,10 +350,10 @@ void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direc list_push(&m->parameters, p); } -int model_param_remove(struct fpga_ip *c, const char *name) +int model_parameter_remove(struct fpga_ip *c, const char *name) { struct model *m = c->_vd; - struct model_param *p; + struct model_parameter *p; p = list_lookup(&m->parameters, name); if (!p) @@ -352,7 +364,7 @@ int model_param_remove(struct fpga_ip *c, const char *name) return 0; } -int model_param_update(struct model_param *p, struct model_param *u) +int model_parameter_update(struct model_parameter *p, struct model_parameter *u) { if (strcmp(p->name, u->name) != 0) return -1; diff --git a/lib/fpga/ips/switch.c b/lib/fpga/ips/switch.c index a901fc740..04f50b438 100644 --- a/lib/fpga/ips/switch.c +++ b/lib/fpga/ips/switch.c @@ -88,43 +88,41 @@ int switch_destroy(struct fpga_ip *c) return 0; } -int switch_parse(struct fpga_ip *c) +int switch_parse(struct fpga_ip *c, json_t *cfg) { - struct fpga_card *f = c->card; struct sw *sw = c->_vd; + int ret; + size_t index; + json_error_t err; + json_t *cfg_path, *cfg_paths = NULL; + list_init(&sw->paths); - config_setting_t *cfg_sw, *cfg_path; + ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s?: o }", + "num_ports", &sw->num_ports, + "paths", &cfg_paths + ); + if (ret) + jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name); - if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports)) - cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name); - - cfg_sw = config_setting_get_member(f->cfg, "paths"); - if (!cfg_sw) + if (!cfg_paths) return 0; /* no switch config available */ - for (int i = 0; i < config_setting_length(cfg_sw); i++) { - cfg_path = config_setting_get_elem(cfg_sw, i); + if (!json_is_array(cfg_paths)) + error("Setting 'paths' of FPGA IP '%s' should be an array of JSON objects", c->name); + json_array_foreach(cfg_paths, index, cfg_path) { struct sw_path *p = alloc(sizeof(struct sw_path)); - int reverse; + int reverse = 0; - if (!config_setting_lookup_bool(cfg_path, "reverse", &reverse)) - reverse = 0; - - if (!config_setting_lookup_string(cfg_path, "in", &p->in) && - !config_setting_lookup_string(cfg_path, "from", &p->in) && - !config_setting_lookup_string(cfg_path, "src", &p->in) && - !config_setting_lookup_string(cfg_path, "source", &p->in)) - cerror(cfg_path, "Path is missing 'in' setting"); - - if (!config_setting_lookup_string(cfg_path, "out", &p->out) && - !config_setting_lookup_string(cfg_path, "to", &p->out) && - !config_setting_lookup_string(cfg_path, "dst", &p->out) && - !config_setting_lookup_string(cfg_path, "dest", &p->out) && - !config_setting_lookup_string(cfg_path, "sink", &p->out)) - cerror(cfg_path, "Path is missing 'out' setting"); + ret = json_unpack_ex(cfg_path, &err, 0, "{ s?: b, s: s, s: s }", + "reverse", &reverse, + "in", &p->in, + "out", &p->out + ); + if (ret) + jerror(&err, "Failed to parse path %zu of FPGA IP '%s'", index, c->name); list_push(&sw->paths, p); diff --git a/lib/hist.c b/lib/hist.c index 448feffac..9e6ccb61c 100644 --- a/lib/hist.c +++ b/lib/hist.c @@ -212,7 +212,6 @@ char * hist_dump(struct hist *h) return buf; } -#ifdef WITH_JSON json_t * hist_json(struct hist *h) { json_t *json_buckets, *json_hist; @@ -257,7 +256,6 @@ int hist_dump_json(struct hist *h, FILE *f) return ret; } -#endif /* WITH_JSON */ int hist_dump_matlab(struct hist *h, FILE *f) { diff --git a/lib/hook.c b/lib/hook.c index 9cb77cf6e..44f0062de 100644 --- a/lib/hook.c +++ b/lib/hook.c @@ -21,7 +21,6 @@ *********************************************************************************/ #include #include -#include #include "timing.h" #include "config.h" @@ -54,18 +53,24 @@ int hook_init(struct hook *h, struct hook_type *vt, struct path *p) return 0; } -int hook_parse(struct hook *h, config_setting_t *cfg) +int hook_parse(struct hook *h, json_t *cfg) { int ret; + json_error_t err; assert(h->state != STATE_DESTROYED); - config_setting_lookup_int(cfg, "priority", &h->priority); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }", + "priority", &h->priority + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); ret = h->_vt->parse ? h->_vt->parse(h, cfg) : 0; if (ret) return ret; + h->cfg = cfg; h->state = STATE_PARSED; return 0; @@ -83,20 +88,11 @@ int hook_parse_cli(struct hook *h, int argc, char *argv[]) h->state = STATE_PARSED; } else { - config_t cfg; - config_setting_t *cfg_root; + h->cfg = json_load_cli(argc, argv); + if (!h->cfg) + return -1; - config_init(&cfg); - - ret = config_read_cli(&cfg, argc, argv); - if (ret) - goto out; - - cfg_root = config_root_setting(&cfg); - - ret = hook_parse(h, cfg_root); - -out: config_destroy(&cfg); + ret = hook_parse(h, h->cfg); } return ret; @@ -204,38 +200,36 @@ int hook_cmp_priority(const void *a, const void *b) return ha->priority - hb->priority; } -int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *o) +int hook_parse_list(struct list *list, json_t *cfg, struct path *o) { - struct plugin *p; + if (!json_is_array(cfg)) + error("Hooks must be configured as a list of objects"); - int ret; - const char *type; + size_t index; + json_t *cfg_hook; + json_array_foreach(cfg, index, cfg_hook) { + int ret; + const char *type; + struct plugin *p; + json_error_t err; - if (!config_setting_is_list(cfg)) - cerror(cfg, "Hooks must be configured as a list of objects"); - - for (int i = 0; i < config_setting_length(cfg); i++) { - config_setting_t *cfg_hook = config_setting_get_elem(cfg, i); - - if (!config_setting_is_group(cfg_hook)) - cerror(cfg_hook, "The 'hooks' setting must be an array of strings."); - - if (!config_setting_lookup_string(cfg_hook, "type", &type)) - cerror(cfg_hook, "Missing setting 'type' for hook"); + ret = json_unpack_ex(cfg_hook, &err, 0, "{ s: s }", "type", &type); + if (ret) + jerror(&err, "Failed to parse hook"); p = plugin_lookup(PLUGIN_TYPE_HOOK, type); if (!p) - continue; /* We ignore all non hook settings in this libconfig object setting */ + jerror(&err, "Unkown hook type '%s'", type); struct hook *h = alloc(sizeof(struct hook)); ret = hook_init(h, &p->hook, o); if (ret) - cerror(cfg_hook, "Failed to initialize hook"); + jerror(&err, "Failed to initialize hook"); ret = hook_parse(h, cfg_hook); if (ret) - cerror(cfg_hook, "Failed to parse hook configuration"); + jerror(&err, "Failed to parse hook configuration"); list_push(list, h); } diff --git a/lib/hooks/convert.c b/lib/hooks/convert.c index db83afe65..399759d1e 100644 --- a/lib/hooks/convert.c +++ b/lib/hooks/convert.c @@ -49,24 +49,28 @@ static int convert_init(struct hook *h) return 0; } -static int convert_parse(struct hook *h, config_setting_t *cfg) +static int convert_parse(struct hook *h, json_t *cfg) { struct convert *p = h->_vd; - const char *mode; + int ret; + json_error_t err; + const char *mode = NULL; - config_setting_lookup_float(cfg, "scale", &p->scale); - config_setting_lookup_int64(cfg, "mask", &p->mask); - - if (!config_setting_lookup_string(cfg, "mode", &mode)) - cerror(cfg, "Missing setting 'mode' for hook '%s'", plugin_name(h->_vt)); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: F, s?: i, s: s }", + "scale", &p->scale, + "mask", &p->mask, + "mode", &mode + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); if (!strcmp(mode, "fixed")) p->mode = TO_FIXED; else if (!strcmp(mode, "float")) p->mode = TO_FLOAT; else - error("Invalid parameter '%s' for hook 'convert'", mode); + error("Invalid 'mode' setting '%s' for hook '%s'", mode, plugin_name(h->_vt)); return 0; } diff --git a/lib/hooks/decimate.c b/lib/hooks/decimate.c index b97bcf670..adc321f31 100644 --- a/lib/hooks/decimate.c +++ b/lib/hooks/decimate.c @@ -41,15 +41,18 @@ static int decimate_init(struct hook *h) return 0; } -static int decimate_parse(struct hook *h, config_setting_t *cfg) +static int decimate_parse(struct hook *h, json_t *cfg) { struct decimate *p = h->_vd; - if (!cfg) - error("Missing configuration for hook: '%s'", plugin_name(h->_vt)); + int ret; + json_error_t err; - if (!config_setting_lookup_int(cfg, "ratio", &p->ratio)) - cerror(cfg, "Missing setting 'ratio' for hook '%s'", plugin_name(h->_vt)); + ret = json_unpack_ex(cfg, &err, 0, "{ s: i }", + "ratio", &p->ratio + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); return 0; } diff --git a/lib/hooks/map.c b/lib/hooks/map.c index 1c203ccd8..b5766805c 100644 --- a/lib/hooks/map.c +++ b/lib/hooks/map.c @@ -51,15 +51,18 @@ static int map_destroy(struct hook *h) return mapping_destroy(&p->mapping); } -static int map_parse(struct hook *h, config_setting_t *cfg) +static int map_parse(struct hook *h, json_t *cfg) { int ret; struct map *p = h->_vd; - config_setting_t *cfg_mapping; + json_error_t err; + json_t *cfg_mapping; - cfg_mapping = config_setting_lookup(cfg, "mapping"); - if (!cfg_mapping || !config_setting_is_array(cfg_mapping)) - return -1; + ret = json_unpack_ex(cfg, &err, 0, "{ s: o }", + "map", &cfg_mapping + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); ret = mapping_parse(&p->mapping, cfg_mapping); if (ret) diff --git a/lib/hooks/print.c b/lib/hooks/print.c index 895437b0e..51f31efde 100644 --- a/lib/hooks/print.c +++ b/lib/hooks/print.c @@ -31,6 +31,8 @@ struct print { struct io output; + struct io_format *format; + const char *uri; }; @@ -38,7 +40,14 @@ static int print_init(struct hook *h) { struct print *p = h->_vd; + struct plugin *pl; + + pl = plugin_lookup(PLUGIN_TYPE_FORMAT, "villas"); + if (!pl) + return -1; + p->uri = NULL; + p->format = &pl->io; return 0; } @@ -46,22 +55,56 @@ static int print_init(struct hook *h) static int print_start(struct hook *h) { struct print *p = h->_vd; + int ret; - return io_open(&p->output, p->uri, "w+"); + ret = io_init(&p->output, p->format, IO_FORMAT_ALL); + if (ret) + return ret; + + ret = io_open(&p->output, p->uri, "w+"); + if (ret) + return ret; + + return 0; } static int print_stop(struct hook *h) { struct print *p = h->_vd; + int ret; - return io_close(&p->output); + ret = io_close(&p->output); + if (ret) + return ret; + + ret = io_destroy(&p->output); + if (ret) + return ret; + + return 0; } -static int print_parse(struct hook *h, config_setting_t *cfg) +static int print_parse(struct hook *h, json_t *cfg) { struct print *p = h->_vd; + struct plugin *pl; + const char *format = NULL; + int ret; + json_error_t err; - config_setting_lookup_string(cfg, "output", &p->uri); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s }", + "output", &p->uri + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); + + if (format) { + pl = plugin_lookup(PLUGIN_TYPE_FORMAT, format); + if (!pl) + jerror(&err, "Invalid format '%s'", format); + + p->format = &pl->io; + } return 0; } diff --git a/lib/hooks/shift_seq.c b/lib/hooks/shift_seq.c index aeab1de1b..153a2e721 100644 --- a/lib/hooks/shift_seq.c +++ b/lib/hooks/shift_seq.c @@ -32,12 +32,18 @@ struct shift { int offset; }; -static int shift_seq_parse(struct hook *h, config_setting_t *cfg) +static int shift_seq_parse(struct hook *h, json_t *cfg) { struct shift *p = h->_vd; - if (!config_setting_lookup_int(cfg, "offset", &p->offset)) - cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt)); + json_error_t err; + int ret; + + ret = json_unpack_ex(cfg, &err, 0, "{ s: i }", + "offset", &p->offset + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); return 0; } diff --git a/lib/hooks/shift_ts.c b/lib/hooks/shift_ts.c index e2c6ab6b8..9f1acb5fe 100644 --- a/lib/hooks/shift_ts.c +++ b/lib/hooks/shift_ts.c @@ -47,13 +47,22 @@ static int shift_ts_init(struct hook *h) return 0; } -static int shift_ts_parse(struct hook *h, config_setting_t *cfg) +static int shift_ts_parse(struct hook *h, json_t *cfg) { struct shift_ts *p = h->_vd; + double offset; + const char *mode = NULL; + int ret; + json_error_t err; - const char *mode; + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: f }", + "mode", &mode, + "offset", &offset + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); - if (config_setting_lookup_string(cfg, "mode", &mode)) { + if (mode) { if (!strcmp(mode, "origin")) p->mode = SHIFT_ORIGIN; else if (!strcmp(mode, "received")) @@ -61,13 +70,9 @@ static int shift_ts_parse(struct hook *h, config_setting_t *cfg) else if (!strcmp(mode, "sent")) p->mode = SHIFT_SENT; else - cerror(cfg, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt)); + jerror(&err, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt)); } - double offset; - if (!config_setting_lookup_float(cfg, "offset", &offset)) - cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt)); - p->offset = time_from_double(offset); return 0; diff --git a/lib/hooks/skip_first.c b/lib/hooks/skip_first.c index a1fb84eb9..231aa1b1b 100644 --- a/lib/hooks/skip_first.c +++ b/lib/hooks/skip_first.c @@ -24,8 +24,6 @@ * @{ */ -#include - #include "hook.h" #include "plugin.h" #include "timing.h" @@ -53,23 +51,33 @@ struct skip_first { }; }; -static int skip_first_parse(struct hook *h, config_setting_t *cfg) +static int skip_first_parse(struct hook *h, json_t *cfg) { struct skip_first *p = h->_vd; double seconds; - if (config_setting_lookup_float(cfg, "seconds", &seconds)) { + int ret; + json_error_t err; + + ret = json_unpack_ex(cfg, &err, 0, "{ s: F }", "seconds", &seconds); + if (!ret) { p->seconds.wait = time_from_double(seconds); p->mode = HOOK_SKIP_MODE_SECONDS; - } - else if (config_setting_lookup_int(cfg, "samples", &p->samples.wait)) { - p->mode = HOOK_SKIP_MODE_SAMPLES; - } - else - cerror(cfg, "Missing setting 'seconds' or 'samples' for hook '%s'", plugin_name(h->_vt)); - return 0; + return 0; + } + + ret = json_unpack_ex(cfg, &err, 0, "{ s: i }", "samples", &p->samples.wait); + if (!ret) { + p->mode = HOOK_SKIP_MODE_SAMPLES; + + return 0; + } + + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); + + return -1; } static int skip_first_restart(struct hook *h) diff --git a/lib/hooks/stats_collect.c b/lib/hooks/stats_collect.c index b0b0e596e..362d4e4f1 100644 --- a/lib/hooks/stats_collect.c +++ b/lib/hooks/stats_collect.c @@ -116,26 +116,35 @@ static int stats_collect_periodic(struct hook *h) return 0; } -static int stats_collect_parse(struct hook *h, config_setting_t *cfg) +static int stats_collect_parse(struct hook *h, json_t *cfg) { struct stats_collect *p = h->_vd; - const char *format, *uri; - if (config_setting_lookup_string(cfg, "format", &format)) { - int fmt; + int ret, fmt; + json_error_t err; + const char *format = NULL; + const char *uri = NULL; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: s?: i, s?: s }" + "format", &format, + "verbose", &p->verbose, + "warmup", &p->warmup, + "buckets", &p->buckets, + "output", &uri + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); + + if (format) { fmt = stats_lookup_format(format); if (fmt < 0) - cerror(cfg, "Invalid statistic output format: %s", format); + jerror(&err, "Invalid statistic output format: %s", format); p->format = fmt; } - config_setting_lookup_bool(cfg, "verbose", &p->verbose); - config_setting_lookup_int(cfg, "warmup", &p->warmup); - config_setting_lookup_int(cfg, "buckets", &p->buckets); - - if (config_setting_lookup_string(cfg, "output", &uri)) + if (uri) p->uri = strdup(uri); return 0; diff --git a/lib/hooks/stats_send.c b/lib/hooks/stats_send.c index 6a95105a5..bd9ace84b 100644 --- a/lib/hooks/stats_send.c +++ b/lib/hooks/stats_send.c @@ -53,35 +53,45 @@ static int stats_send_init(struct hook *h) return 0; } -static int stats_send_parse(struct hook *h, config_setting_t *cfg) +static int stats_send_parse(struct hook *h, json_t *cfg) { struct stats_send *p = h->_vd; assert(h->path && h->path->super_node); - const char *dest, *mode; + const char *dest = NULL; + const char *mode = NULL; - if (config_setting_lookup_string(cfg, "destination", &dest)) { + int ret; + json_error_t err; + + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s, s?: i }" + "destination", &dest, + "mode", &mode, + "decimation", &p->decimation + ); + if (ret) + jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt)); + + if (dest) { assert(h->path); p->dest = list_lookup(&h->path->super_node->nodes, dest); if (!p->dest) - cerror(cfg, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt)); + jerror(&err, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt)); } else - cerror(cfg, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt)); + jerror(&err, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt)); - if (config_setting_lookup_string(cfg, "mode", &mode)) { + if (mode) { if (!strcmp(mode, "periodic")) p->mode = STATS_SEND_MODE_PERIODIC; else if (!strcmp(mode, "read")) p->mode = STATS_SEND_MODE_READ; else - cerror(cfg, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt)); + jerror(&err, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt)); } - config_setting_lookup_int(cfg, "decimation", &p->decimation); - return 0; } diff --git a/lib/kernel/tc.c b/lib/kernel/tc.c index a1e2f0e33..311aefb26 100644 --- a/lib/kernel/tc.c +++ b/lib/kernel/tc.c @@ -35,10 +35,32 @@ #include "utils.h" -int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem) +int tc_parse(struct rtnl_qdisc **netem, json_t *cfg) { const char *str; - int val; + int ret, val; + + json_t *cfg_distribution = NULL; + json_t *cfg_limit = NULL; + json_t *cfg_delay = NULL; + json_t *cfg_jitter = NULL; + json_t *cfg_loss = NULL; + json_t *cfg_duplicate = NULL; + json_t *cfg_corruption = NULL; + + json_error_t err; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: i, s?: i, s?: i, s?: i, s?: i, s?: i }", + "distribution", &cfg_distribution, + "limit", &cfg_limit, + "delay", &cfg_delay, + "jitter", &cfg_jitter, + "loss", &cfg_loss, + "duplicate", &cfg_duplicate, + "corruption", &cfg_corruption + ); + if (ret) + jerror(&err, "Failed to parse setting network emulation settings"); struct rtnl_qdisc *ne = rtnl_qdisc_alloc(); if (!ne) @@ -46,51 +68,67 @@ int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem) rtnl_tc_set_kind(TC_CAST(ne), "netem"); - if (config_setting_lookup_string(cfg, "distribution", &str)) { + if (cfg_distribution) { + str = json_string_value(cfg_distribution); + if (!str) + error("Setting 'distribution' must be a JSON string"); + if (rtnl_netem_set_delay_distribution(ne, str)) - cerror(cfg, "Invalid delay distribution '%s' in netem config", str); + error("Invalid delay distribution '%s' in netem config", str); } - if (config_setting_lookup_int(cfg, "limit", &val)) { - if (val <= 0) - cerror(cfg, "Invalid value '%d' for limit setting", val); + if (cfg_limit) { + val = json_integer_value(cfg_limit); + + if (!json_is_integer(cfg_limit) || val <= 0) + error("Setting 'limit' must be a positive integer"); rtnl_netem_set_limit(ne, val); } else rtnl_netem_set_limit(ne, 0); - if (config_setting_lookup_int(cfg, "delay", &val)) { - if (val <= 0) - cerror(cfg, "Invalid value '%d' for delay setting", val); + if (cfg_delay) { + val = json_integer_value(cfg_delay); + + if (!json_is_integer(cfg_delay) || val <= 0) + error("Setting 'delay' must be a positive integer"); rtnl_netem_set_delay(ne, val); } - if (config_setting_lookup_int(cfg, "jitter", &val)) { - if (val <= 0) - cerror(cfg, "Invalid value '%d' for jitter setting", val); + if (cfg_jitter) { + val = json_integer_value(cfg_jitter); + + if (!json_is_integer(cfg_jitter) || val <= 0) + error("Setting 'jitter' must be a positive integer"); rtnl_netem_set_jitter(ne, val); } - if (config_setting_lookup_int(cfg, "loss", &val)) { - if (val < 0 || val > 100) - cerror(cfg, "Invalid percentage value '%d' for loss setting", val); + if (cfg_loss) { + val = json_integer_value(cfg_loss); + + if (!json_is_integer(cfg_loss) || val < 0 || val > 100) + error("Setting 'loss' must be a positive integer within the range [ 0, 100 ]"); rtnl_netem_set_loss(ne, val); } - if (config_setting_lookup_int(cfg, "duplicate", &val)) { - if (val < 0 || val > 100) - cerror(cfg, "Invalid percentage value '%d' for duplicate setting", val); + if (cfg_duplicate) { + val = json_integer_value(cfg_duplicate); + + if (!json_is_integer(cfg_duplicate) || val < 0 || val > 100) + error("Setting 'duplicate' must be a positive integer within the range [ 0, 100 ]"); rtnl_netem_set_duplicate(ne, val); } - if (config_setting_lookup_int(cfg, "corruption", &val)) { - if (val < 0 || val > 100) - cerror(cfg, "Invalid percentage value '%d' for corruption setting", val); + if (cfg_corruption) { + val = json_integer_value(cfg_corruption); + + if (!json_is_integer(cfg_corruption) || val < 0 || val > 100) + error("Setting 'corruption' must be a positive integer within the range [ 0, 100 ]"); rtnl_netem_set_corruption_probability(ne, val); } diff --git a/lib/log_config.c b/lib/log_config.c index d60ccd654..f8eaf21c0 100644 --- a/lib/log_config.c +++ b/lib/log_config.c @@ -1,4 +1,4 @@ -/** Logging routines that depend on libconfig. +/** Logging routines that depend on jansson. * * @author Steffen Vogel * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC @@ -28,35 +28,39 @@ #include "log.h" #include "log_config.h" #include "utils.h" +#include "string.h" -int log_parse(struct log *l, config_setting_t *cfg) +int log_parse(struct log *l, json_t *cfg) { - const char *fac, *pth; - int lvl; + const char *facilities = NULL; + const char *path = NULL; + int ret; - if (!config_setting_is_group(cfg)) - cerror(cfg, "Setting 'log' must be a group."); + json_error_t err; - if (config_setting_lookup_int(cfg, "level", &lvl)) - l->level = lvl; + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: s, s?: s }", + "level", &l->level, + "file", &path, + "facilities", &facilities + ); + if (ret) + jerror(&err, "Failed to parse logging configuration"); - if (config_setting_lookup_string(cfg, "file", &pth)) - l->path = pth; + if (path) + l->path = strdup(path); - if (config_setting_lookup_string(cfg, "facilities", &fac)) - log_set_facility_expression(l, fac); + if (facilities) + log_set_facility_expression(l, facilities); l->state = STATE_PARSED; return 0; } -void cerror(config_setting_t *cfg, const char *fmt, ...) +void jerror(json_error_t *err, const char *fmt, ...) { va_list ap; char *buf = NULL; - const char *file; - int line; struct log *l = global_log ? global_log : &default_log; @@ -64,12 +68,10 @@ void cerror(config_setting_t *cfg, const char *fmt, ...) vstrcatf(&buf, fmt, ap); va_end(ap); - line = config_setting_source_line(cfg); - file = config_setting_source_file(cfg); - if (!file) - file = config_setting_get_hook(config_root_setting(cfg->config)); - - log_print(l, LOG_LVL_ERROR, "%s in %s:%u", buf, file, line); + log_print(l, LOG_LVL_ERROR, "%s:", buf); + { INDENT + log_print(l, LOG_LVL_ERROR, "%s in %s:%d:%d", err->text, err->source, err->line, err->column); + } free(buf); diff --git a/lib/mapping.c b/lib/mapping.c index ae0896d17..cc5d8f295 100644 --- a/lib/mapping.c +++ b/lib/mapping.c @@ -162,11 +162,11 @@ invalid_format: return -1; } -int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg) +int mapping_entry_parse(struct mapping_entry *e, json_t *cfg) { const char *str; - str = config_setting_get_string(cfg); + str = json_string_value(cfg); if (!str) return -1; @@ -195,27 +195,23 @@ int mapping_destroy(struct mapping *m) return 0; } -int mapping_parse(struct mapping *m, config_setting_t *cfg) +int mapping_parse(struct mapping *m, json_t *cfg) { int ret; assert(m->state == STATE_INITIALIZED); - if (!config_setting_is_array(cfg)) + if (!json_is_array(cfg)) return -1; m->real_length = 0; - for (int i = 0; i < config_setting_length(cfg); i++) { - config_setting_t *cfg_mapping; - - cfg_mapping = config_setting_get_elem(cfg, i); - if (!cfg_mapping) - return -1; - + size_t index; + json_t *cfg_entry; + json_array_foreach(cfg, index, cfg_entry) { struct mapping_entry *e = alloc(sizeof(struct mapping_entry)); - ret = mapping_entry_parse(e, cfg_mapping); + ret = mapping_entry_parse(e, cfg_entry); if (ret) return ret; diff --git a/lib/node.c b/lib/node.c index 09dda4327..7d89eec18 100644 --- a/lib/node.c +++ b/lib/node.c @@ -21,7 +21,6 @@ *********************************************************************************/ #include -#include #include "sample.h" #include "node.h" @@ -52,28 +51,32 @@ int node_init(struct node *n, struct node_type *vt) return 0; } -int node_parse(struct node *n, config_setting_t *cfg) +int node_parse(struct node *n, json_t *cfg, const char *name) { struct plugin *p; - const char *type, *name; int ret; - name = config_setting_name(cfg); + json_error_t err; - if (!config_setting_lookup_string(cfg, "type", &type)) - cerror(cfg, "Missing node type"); + const char *type; + + n->name = strdup(name); + + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: i }", + "type", &type, + "vectorize", &n->vectorize + ); + if (ret) + jerror(&err, "Failed to parse node '%s'", node_name(n)); p = plugin_lookup(PLUGIN_TYPE_NODE, type); assert(&p->node == n->_vt); - config_setting_lookup_int(cfg, "vectorize", &n->vectorize); - - n->name = strdup(name); - ret = n->_vt->parse ? n->_vt->parse(n, cfg) : 0; if (ret) - cerror(cfg, "Failed to parse node '%s'", node_name(n)); + error("Failed to parse node '%s'", node_name(n)); + n->cfg = cfg; n->state = STATE_PARSED; return ret; @@ -85,10 +88,9 @@ int node_parse_cli(struct node *n, int argc, char *argv[]) assert(n->_vt); - n->vectorize = 1; - n->name = "cli"; - if (n->_vt->parse_cli) { + n->name = strdup("cli"); + ret = n->_vt->parse_cli(n, argc, argv); if (ret) return ret; @@ -96,21 +98,11 @@ int node_parse_cli(struct node *n, int argc, char *argv[]) n->state = STATE_PARSED; } else { - config_t cfg; - config_setting_t *cfg_root; + n->cfg = json_load_cli(argc, argv); + if (!n->cfg) + return -1; - config_init(&cfg); - - ret = config_read_cli(&cfg, argc, argv); - if (ret) - goto out; - - cfg_root = config_root_setting(&cfg); - - ret = node_parse(n, cfg_root); - -out: - config_destroy(&cfg); + ret = node_parse(n, n->cfg, "cli"); } return ret; @@ -279,47 +271,57 @@ int node_reverse(struct node *n) return n->_vt->reverse ? n->_vt->reverse(n) : -1; } -int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all) +int node_parse_list(struct list *list, json_t *cfg, struct list *all) { - const char *str; struct node *node; + const char *str; + char *allstr = NULL; - 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"); + size_t index; + json_t *elm; + + switch (json_typeof(cfg)) { + case JSON_STRING: + str = json_string_value(cfg); + node = list_lookup(all, str); + if (!node) + goto invalid2; + + list_push(list, 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); + case JSON_ARRAY: + json_array_foreach(cfg, index, elm) { + if (!json_is_string(elm)) + goto invalid; - str = config_setting_get_string(elm); - if (str) { - node = list_lookup(all, str); - if (!node) - cerror(elm, "Unknown outgoing node '%s'", str); - else if (node->_vt->write == NULL) - cerror(cfg, "Output node '%s' is not supported as a sink.", node_name(node)); + node = list_lookup(all, json_string_value(elm)); + if (!node) - list_push(list, node); - } - else - cerror(cfg, "Invalid outgoing node"); + + list_push(list, node); } break; default: - cerror(cfg, "Invalid output node(s)"); + goto invalid; } + return 0; + +invalid: + error("The node list must be an a single or an array of strings referring to the keys of the 'nodes' section"); + + return -1; + +invalid2: + for (size_t i = 0; i < list_length(all); i++) { + struct node *n = list_at(all, i); + + strcatf(&allstr, " %s", node_name_short(n)); + } + + error("Unknown node '%s'. Choose of one of: %s", str, allstr); + return 0; } diff --git a/lib/nodes/cbuilder.c b/lib/nodes/cbuilder.c index 48e4032e9..712dfded5 100644 --- a/lib/nodes/cbuilder.c +++ b/lib/nodes/cbuilder.c @@ -11,33 +11,43 @@ #include "nodes/cbuilder.h" -int cbuilder_parse(struct node *n, config_setting_t *cfg) +int cbuilder_parse(struct node *n, json_t *cfg) { struct cbuilder *cb = n->_vd; - config_setting_t *cfg_params; + json_t *cfg_param, *cfg_params = NULL; const char *model; - if (!config_setting_lookup_float(cfg, "timestep", &cb->timestep)) - cerror(cfg, "CBuilder model requires 'timestep' setting"); + int ret; + size_t index; + json_error_t err; - if (!config_setting_lookup_string(cfg, "model", &model)) - cerror(cfg, "CBuilder model requires 'model' setting"); + ret = json_unpack_ex(cfg, &err, 0, "{ s: f, s: s, s: b }", + "timestep", &cb->timestep, + "model", &model, + "parameters", &cfg_params + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); cb->model = (struct cbuilder_model *) plugin_lookup(PLUGIN_TYPE_MODEL_CBUILDER, model); if (!cb->model) - cerror(cfg, "Unknown model '%s'", model); + error("Unknown model '%s' of node %s", model, node_name(n)); - cfg_params = config_setting_get_member(cfg, "parameters"); if (cfg_params) { - if (!config_setting_is_array(cfg_params)) - cerror(cfg_params, "Model parameters must be an array of numbers!"); + if (!json_is_array(cfg_params)) + error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n)); - cb->paramlen = config_setting_length(cfg_params); + cb->paramlen = json_array_size(cfg_params); cb->params = alloc(cb->paramlen * sizeof(double)); - for (int i = 0; i < cb->paramlen; i++) - cb->params[i] = config_setting_get_float_elem(cfg_params, i); + json_array_foreach(cfg_params, index, cfg_param) { + if (json_is_number(cfg_param)) + error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n)); + + cb->params[index] = json_number_value(cfg_params); + + } } return 0; diff --git a/lib/nodes/file.c b/lib/nodes/file.c index d9677666d..1cc50e38a 100644 --- a/lib/nodes/file.c +++ b/lib/nodes/file.c @@ -64,15 +64,29 @@ static AFILE * file_reopen(struct file_direction *dir) return afopen(dir->uri, dir->mode); } -static int file_parse_direction(config_setting_t *cfg, struct file *f, int d) +static int file_parse_direction(json_t *cfg, struct file *f, int d) { struct file_direction *dir = (d == FILE_READ) ? &f->read : &f->write; + int ret; + json_error_t err; - if (!config_setting_lookup_string(cfg, "uri", &dir->fmt)) - return -1; + const char *format = NULL; + const char *mode = NULL; - if (!config_setting_lookup_string(cfg, "mode", &dir->mode)) - dir->mode = (d == FILE_READ) ? "r" : "w+"; + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s }", + "uri", &format, + "mode", &mode + ); + if (ret) + jerror(&err, "Failed to "); + + if (format) + dir->format = strdup(format); + + if (mode) + dir->mode = strdup(mode); + else + dir->mode = strdup(d == FILE_READ ? "r" : "w+"); return 0; } @@ -104,30 +118,61 @@ static struct timespec file_calc_read_offset(const struct timespec *first, const } } -int file_parse(struct node *n, config_setting_t *cfg) +int file_parse(struct node *n, json_t *cfg) { struct file *f = n->_vd; - config_setting_t *cfg_in, *cfg_out; + json_t *cfg_in = NULL; + json_t *cfg_out = NULL; + + int ret; + json_error_t err; + + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }", + "in", &cfg_in, + "out", &cfg_out + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); - cfg_out = config_setting_get_member(cfg, "out"); if (cfg_out) { if (file_parse_direction(cfg_out, f, FILE_WRITE)) - cerror(cfg_out, "Failed to parse output file for node %s", node_name(n)); + error("Failed to parse output file for node %s", node_name(n)); - if (!config_setting_lookup_bool(cfg_out, "flush", &f->flush)) - f->flush = 0; + f->flush = 0; + + ret = json_unpack_ex(cfg_out, &err, 0, "{ s?: b }", "flush", &f->flush); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); } - cfg_in = config_setting_get_member(cfg, "in"); if (cfg_in) { - const char *eof; + const char *eof = NULL; + const char *epoch_mode = NULL; + double epoch_flt = 0; + + /* Default values */ + f->read_rate = 0; + f->read_eof = FILE_EOF_EXIT; + f->read_epoch_mode = FILE_EPOCH_DIRECT; if (file_parse_direction(cfg_in, f, FILE_READ)) - cerror(cfg_in, "Failed to parse input file for node %s", node_name(n)); + error("Failed to parse input file for node %s", node_name(n)); + + ret = json_unpack_ex(cfg_in, &err, 0, "{ s?: s, s?: f, s?: s, s?: f }", + "eof", &eof, + "rate", &f->read_rate, + "epoch_mode", &epoch_mode, + "epoch", &epoch_flt + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + + f->read_epoch = time_from_double(epoch_flt); /* More read specific settings */ - if (config_setting_lookup_string(cfg_in, "eof", &eof)) { + if (eof) { if (!strcmp(eof, "exit")) f->read_eof = FILE_EOF_EXIT; else if (!strcmp(eof, "rewind")) @@ -135,22 +180,10 @@ int file_parse(struct node *n, config_setting_t *cfg) else if (!strcmp(eof, "wait")) f->read_eof = FILE_EOF_WAIT; else - cerror(cfg_in, "Invalid mode '%s' for 'eof' setting", eof); + error("Invalid mode '%s' for 'eof' setting of node %s", eof, node_name(n)); } - else - f->read_eof = FILE_EOF_EXIT; - if (!config_setting_lookup_float(cfg_in, "rate", &f->read_rate)) - f->read_rate = 0; /* Disable fixed rate sending. Using timestamps of file instead */ - - double epoch_flt; - if (!config_setting_lookup_float(cfg_in, "epoch", &epoch_flt)) - epoch_flt = 0; - - f->read_epoch = time_from_double(epoch_flt); - - const char *epoch_mode; - if (config_setting_lookup_string(cfg_in, "epoch_mode", &epoch_mode)) { + if (epoch_mode) { if (!strcmp(epoch_mode, "direct")) f->read_epoch_mode = FILE_EPOCH_DIRECT; else if (!strcmp(epoch_mode, "wait")) @@ -162,10 +195,8 @@ int file_parse(struct node *n, config_setting_t *cfg) else if (!strcmp(epoch_mode, "original")) f->read_epoch_mode = FILE_EPOCH_ORIGINAL; else - cerror(cfg_in, "Invalid value '%s' for setting 'epoch_mode'", epoch_mode); + error("Invalid value '%s' for setting 'epoch_mode' of node %s", epoch_mode, node_name(n)); } - else - f->read_epoch_mode = FILE_EPOCH_DIRECT; } n->_vd = f; @@ -178,7 +209,7 @@ char * file_print(struct node *n) struct file *f = n->_vd; char *buf = NULL; - if (f->read.fmt) { + if (f->read.format) { const char *epoch_str = NULL; switch (f->read_epoch_mode) { case FILE_EPOCH_DIRECT: epoch_str = "direct"; break; @@ -196,7 +227,7 @@ char * file_print(struct node *n) } strcatf(&buf, "in=%s, mode=%s, eof=%s, epoch_mode=%s, epoch=%.2f", - f->read.uri ? f->read.uri : f->read.fmt, + f->read.uri ? f->read.uri : f->read.format, f->read.mode, eof_str, epoch_str, @@ -207,9 +238,9 @@ char * file_print(struct node *n) strcatf(&buf, ", rate=%.1f", f->read_rate); } - if (f->write.fmt) { + if (f->write.format) { strcatf(&buf, ", out=%s, mode=%s", - f->write.uri ? f->write.uri : f->write.fmt, + f->write.uri ? f->write.uri : f->write.format, f->write.mode ); } @@ -241,9 +272,9 @@ int file_start(struct node *n) struct timespec now = time_now(); int ret; - if (f->read.fmt) { + if (f->read.format) { /* Prepare file name */ - f->read.uri = file_format_name(f->read.fmt, &now); + f->read.uri = file_format_name(f->read.format, &now); /* Open file */ f->read.handle = file_reopen(&f->read); @@ -262,9 +293,10 @@ int file_start(struct node *n) /* Get timestamp of first line */ if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) { struct sample s; + struct sample *smps[] = { &s }; s.capacity = 0; - ret = io_format_villas_fscan(f->read.handle->file, &s, NULL); + ret = io_format_villas_fscan(f->read.handle->file, smps, 1, NULL); if (ret < 0) error("Failed to read first timestamp of node %s", node_name(n)); @@ -274,9 +306,9 @@ int file_start(struct node *n) } } - if (f->write.fmt) { + if (f->write.format) { /* Prepare file name */ - f->write.uri = file_format_name(f->write.fmt, &now); + f->write.uri = file_format_name(f->write.format, &now); /* Open file */ f->write.handle = file_reopen(&f->write); @@ -307,15 +339,14 @@ int file_stop(struct node *n) int file_read(struct node *n, struct sample *smps[], unsigned cnt) { struct file *f = n->_vd; - struct sample *s = smps[0]; int values, flags; uint64_t ex; assert(f->read.handle); assert(cnt == 1); -retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get message and timestamp */ - if (values < 0) { +retry: values = io_format_villas_fscan(f->read.handle->file, smps, 1, &flags); /* Get message and timestamp */ + if (values <= 0) { if (afeof(f->read.handle)) { switch (f->read_eof) { case FILE_EOF_REWIND: @@ -345,14 +376,14 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) { if (!f->read_rate || aftell(f->read.handle) == 0) { - s->ts.origin = time_add(&s->ts.origin, &f->read_offset); + smps[0]->ts.origin = time_add(&smps[0]->ts.origin, &f->read_offset); - ex = timerfd_wait_until(f->read_timer, &s->ts.origin); + ex = timerfd_wait_until(f->read_timer, &smps[0]->ts.origin); } else { /* Wait with fixed rate delay */ ex = timerfd_wait(f->read_timer); - s->ts.origin = time_now(); + smps[0]->ts.origin = time_now(); } /* Check for overruns */ @@ -368,12 +399,11 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get int file_write(struct node *n, struct sample *smps[], unsigned cnt) { struct file *f = n->_vd; - struct sample *s = smps[0]; assert(f->write.handle); assert(cnt == 1); - io_format_villas_fprint(f->write.handle->file, s, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET); + io_format_villas_fprint(f->write.handle->file, smps, cnt, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET); if (f->flush) afflush(f->write.handle); diff --git a/lib/nodes/fpga.c b/lib/nodes/fpga.c index 557d86620..76856e87e 100644 --- a/lib/nodes/fpga.c +++ b/lib/nodes/fpga.c @@ -34,7 +34,6 @@ void fpga_dump(struct fpga *f) int fpga_init(struct super_node *sn) { int ret; - config_setting_t *cfg, *cfg_fpgas; ret = pci_init(&pci); if (ret) @@ -44,6 +43,9 @@ int fpga_init(struct super_node *sn) if (ret) error("Failed to initiliaze VFIO sub-system"); +#if 0 + json_t *cfg, *cfg_fpgas; + /* Parse FPGA configuration */ cfg = config_root_setting(&sn->cfg); cfg_fpgas = config_setting_lookup(cfg, "fpgas"); @@ -53,7 +55,7 @@ int fpga_init(struct super_node *sn) ret = fpga_card_parse_list(&cards, cfg_fpgas); if (ret) cerror(cfg, "Failed to parse VILLASfpga config"); - +#endif return 0; } @@ -76,7 +78,7 @@ int fpga_deinit() return 0; } -int fpga_parse(struct node *n, config_setting_t *cfg) +int fpga_parse(struct node *n, json_t *cfg) { struct fpga *f = n->_vd; struct fpga_card *card; @@ -85,11 +87,18 @@ int fpga_parse(struct node *n, config_setting_t *cfg) char *cpy, *card_name, *ip_name; const char *dm; - if (!config_setting_lookup_string(cfg, "datamover", &dm)) - cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n)); + json_error_t err; + int ret; - if (!config_setting_lookup_bool(cfg, "use_irqs", &f->use_irqs)) - f->use_irqs = false; + /* Default values */ + f->use_irqs = false; + + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: b }", + "datamover", &dm, + "use_irqs", &f->use_irqs + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); cpy = strdup(dm); /* strtok can not operate on type const char * */ @@ -98,13 +107,13 @@ int fpga_parse(struct node *n, config_setting_t *cfg) card = list_lookup(&cards, card_name); if (!card) - cerror(cfg, "There is no FPGA card named '%s", card_name); + error("There is no FPGA card named '%s' used by node %s", card_name, node_name(n)); ip = list_lookup(&card->ips, ip_name); if (!ip) - cerror(cfg, "There is no datamover named '%s' on the FPGA card '%s'", ip_name, card_name); + error("There is no datamover named '%s' on the FPGA card '%s' used by node %s", ip_name, card_name, node_name(n)); if (ip->_vt->type != FPGA_IP_TYPE_DM_DMA && ip->_vt->type != FPGA_IP_TYPE_DM_FIFO) - cerror(cfg, "The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name); + error("The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name); free(cpy); diff --git a/lib/nodes/loopback.c b/lib/nodes/loopback.c index dcb3c2761..995a8d055 100644 --- a/lib/nodes/loopback.c +++ b/lib/nodes/loopback.c @@ -27,15 +27,23 @@ #include "nodes/loopback.h" #include "memory.h" -int loopback_parse(struct node *n, config_setting_t *cfg) +int loopback_parse(struct node *n, json_t *cfg) { struct loopback *l = n->_vd; - if (!config_setting_lookup_int(cfg, "queuelen", &l->queuelen)) - l->queuelen = DEFAULT_QUEUELEN; + json_error_t err; + int ret; - if (!config_setting_lookup_int(cfg, "samplelen", &l->samplelen)) - l->samplelen = DEFAULT_SAMPLELEN; + /* Default values */ + l->queuelen = DEFAULT_QUEUELEN; + l->samplelen = DEFAULT_SAMPLELEN; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i }", + "queuelen", &l->queuelen, + "samplelen", &l->samplelen + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); return 0; } diff --git a/lib/nodes/nanomsg.c b/lib/nodes/nanomsg.c index c442ff2ea..10d588819 100644 --- a/lib/nodes/nanomsg.c +++ b/lib/nodes/nanomsg.c @@ -46,25 +46,28 @@ int nanomsg_reverse(struct node *n) return 0; } -static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg) +static int nanomsg_parse_endpoints(struct list *l, json_t *cfg) { const char *ep; - switch (config_setting_type(cfg)) { - case CONFIG_TYPE_LIST: - case CONFIG_TYPE_ARRAY: - for (int j = 0; j < config_setting_length(cfg); j++) { - const char *ep = config_setting_get_string_elem(cfg, j); + size_t index; + json_t *cfg_val; + + switch (json_typeof(cfg)) { + case JSON_ARRAY: + json_array_foreach(cfg, index, cfg_val) { + ep = json_string_value(cfg_val); + if (!ep) + return -1; list_push(l, strdup(ep)); } break; - case CONFIG_TYPE_STRING: - ep = config_setting_get_string(cfg); + case JSON_STRING: + ep = json_string_value(cfg); list_push(l, strdup(ep)); - break; default: @@ -74,28 +77,36 @@ static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg) return 0; } -int nanomsg_parse(struct node *n, config_setting_t *cfg) +int nanomsg_parse(struct node *n, json_t *cfg) { int ret; struct nanomsg *m = n->_vd; - config_setting_t *cfg_pub, *cfg_sub; + json_error_t err; + + json_t *cfg_pub = NULL; + json_t *cfg_sub = NULL; list_init(&m->publisher.endpoints); list_init(&m->subscriber.endpoints); - cfg_pub = config_setting_lookup(cfg, "publish"); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }", + "publish", &cfg_pub, + "subscribe", &cfg_sub + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + if (cfg_pub) { ret = nanomsg_parse_endpoints(&m->publisher.endpoints, cfg_pub); if (ret < 0) - cerror(cfg_pub, "Invalid type for 'publish' setting of node %s", node_name(n)); + error("Invalid type for 'publish' setting of node %s", node_name(n)); } - cfg_sub = config_setting_lookup(cfg, "subscribe"); if (cfg_sub) { ret = nanomsg_parse_endpoints(&m->subscriber.endpoints, cfg_sub); if (ret < 0) - cerror(cfg_pub, "Invalid type for 'subscribe' setting of node %s", node_name(n)); + error("Invalid type for 'subscribe' setting of node %s", node_name(n)); } return 0; diff --git a/lib/nodes/ngsi.c b/lib/nodes/ngsi.c index 9167c7660..2bc3f2cc8 100644 --- a/lib/nodes/ngsi.c +++ b/lib/nodes/ngsi.c @@ -197,26 +197,31 @@ static int ngsi_parse_entity(json_t *entity, struct ngsi *i, struct sample *smps return cnt; } -static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg) +static int ngsi_parse_mapping(struct list *mapping, json_t *cfg) { - if (!config_setting_is_array(cfg)) + if (!json_is_array(cfg)) return -1; list_init(mapping); - for (int j = 0; j < config_setting_length(cfg); j++) { - const char *token = config_setting_get_string_elem(cfg, j); + size_t index; + json_t *cfg_token; + + json_array_foreach(cfg, index, cfg_token) { + const char *token; + + token = json_string_value(cfg_token); if (!token) return -2; struct ngsi_attribute *a = alloc(sizeof(struct ngsi_attribute)); - a->index = j; + a->index = index; /* Parse Attribute: AttributeName(AttributeType) */ int bytes; if (sscanf(token, "%m[^(](%m[^)])%n", &a->name, &a->type, &bytes) != 2) - cerror(cfg, "Invalid mapping token: '%s'", token); + error("Invalid mapping token: '%s'", token); token += bytes; @@ -241,7 +246,7 @@ static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg) .name = "index", .type = "integer" }; - assert(asprintf(&i.value, "%u", j)); + assert(asprintf(&i.value, "%zu", index)); list_push(&a->metadata, memdup(&s, sizeof(s))); list_push(&a->metadata, memdup(&i, sizeof(i))); @@ -387,18 +392,6 @@ out: json_decref(request); int ngsi_init(struct super_node *sn) { - config_setting_t *cfg; - - cfg = config_root_setting(&sn->cfg); - - const char *tname; - if (config_setting_lookup_string(cfg, "name", &tname)) - name = strdup(tname); - else { - name = alloc(128); /** @todo missing free */ - gethostname((char *) name, 128); - } - return curl_global_init(CURL_GLOBAL_ALL); } @@ -411,37 +404,36 @@ int ngsi_deinit() return 0; } -int ngsi_parse(struct node *n, config_setting_t *cfg) +int ngsi_parse(struct node *n, json_t *cfg) { struct ngsi *i = n->_vd; - if (!config_setting_lookup_string(cfg, "access_token", &i->access_token)) - i->access_token = NULL; /* disabled by default */ + int ret; + json_error_t err; + json_t *cfg_mapping; - if (!config_setting_lookup_string(cfg, "endpoint", &i->endpoint)) - cerror(cfg, "Missing NGSI endpoint for node %s", node_name(n)); + /* Default values */ + i->access_token = NULL; /* disabled by default */ + i->ssl_verify = 1; /* verify by default */ + i->timeout = 1; /* default value */ + i->rate = 5; /* default value */ - if (!config_setting_lookup_string(cfg, "entity_id", &i->entity_id)) - cerror(cfg, "Missing NGSI entity ID for node %s", node_name(n)); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: s, s: s, s: s, s?: b, s?: f, s?: f }", + "access_token", &i->access_token, + "endpoint", &i->endpoint, + "entity_id", &i->entity_id, + "entity_type", &i->entity_type, + "ssl_verify", &i->ssl_verify, + "timeout", &i->timeout, + "rate", &i->rate, + "mapping", &cfg_mapping + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); - if (!config_setting_lookup_string(cfg, "entity_type", &i->entity_type)) - cerror(cfg, "Missing NGSI entity type for node %s", node_name(n)); - - if (!config_setting_lookup_bool(cfg, "ssl_verify", &i->ssl_verify)) - i->ssl_verify = 1; /* verify by default */ - - if (!config_setting_lookup_float(cfg, "timeout", &i->timeout)) - i->timeout = 1; /* default value */ - - if (!config_setting_lookup_float(cfg, "rate", &i->rate)) - i->rate = 5; /* default value */ - - config_setting_t *cfg_mapping = config_setting_get_member(cfg, "mapping"); - if (!cfg_mapping) - cerror(cfg, "Missing mapping for node %s", node_name(n)); - - if (ngsi_parse_mapping(&i->mapping, cfg_mapping)) - cerror(cfg_mapping, "Invalid mapping for node %s", node_name(n)); + ret = ngsi_parse_mapping(&i->mapping, cfg_mapping); + if (ret) + error("Invalid setting 'mapping' of node %s", node_name(n)); return 0; } diff --git a/lib/nodes/opal.c b/lib/nodes/opal.c index 6fe47f826..e48004be9 100644 --- a/lib/nodes/opal.c +++ b/lib/nodes/opal.c @@ -144,13 +144,20 @@ int opal_print_global() return 0; } -int opal_parse(struct node *n, config_setting_t *cfg) +int opal_parse(struct node *n, json_t *cfg) { struct opal *o = n->_vd; - config_setting_lookup_int(cfg, "send_id", &o->send_id); - config_setting_lookup_int(cfg, "recv_id", &o->recv_id); - config_setting_lookup_bool(cfg, "reply", &o->reply); + int ret; + json_error_t err; + + ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: b }", + "send_id", &o->send_id, + "recv_id", &o->recv_id, + "reply", &o->reply + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); return 0; } diff --git a/lib/nodes/shmem.c b/lib/nodes/shmem.c index f98649bfd..af698ed6c 100644 --- a/lib/nodes/shmem.c +++ b/lib/nodes/shmem.c @@ -36,44 +36,49 @@ #include "timing.h" #include "utils.h" -int shmem_parse(struct node *n, config_setting_t *cfg) +int shmem_parse(struct node *n, json_t *cfg) { struct shmem *shm = n->_vd; + const char *val; - if (!config_setting_lookup_string(cfg, "out_name", &shm->out_name)) - cerror(cfg, "Missing shared memory output queue name"); + int ret; + json_t *cfg_exec = NULL; + json_error_t err; - if (!config_setting_lookup_string(cfg, "in_name", &shm->in_name)) - cerror(cfg, "Missing shared memory input queue name"); + /* Default values */ + shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize); + shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN; + shm->conf.polling = false; + shm->exec = NULL; - if (!config_setting_lookup_int(cfg, "queuelen", &shm->conf.queuelen)) - shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize); + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s: s, s?: i, s?: i, s?: b, s?: o }", + "out_name", &shm->out_name, + "in_name", &shm->in_name, + "queuelen", &shm->conf.queuelen, + "samplelen", &shm->conf.samplelen, + "polling", &shm->conf.polling, + "exec", &cfg_exec + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); - if (!config_setting_lookup_int(cfg, "samplelen", &shm->conf.samplelen)) - shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN; + if (cfg_exec) { + if (!json_is_array(cfg_exec)) + error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n)); - if (!config_setting_lookup_bool(cfg, "polling", &shm->conf.polling)) - shm->conf.polling = false; + shm->exec = alloc(sizeof(char *) * (json_array_size(cfg_exec) + 1)); - config_setting_t *exec_cfg = config_setting_lookup(cfg, "exec"); - if (!exec_cfg) - shm->exec = NULL; - else { - if (!config_setting_is_array(exec_cfg)) - cerror(exec_cfg, "Invalid format for exec"); + size_t index; + json_t *cfg_val; + json_array_foreach(cfg_exec, index, cfg_val) { + val = json_string_value(cfg_exec); + if (!val) + error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n)); - shm->exec = alloc(sizeof(char *) * (config_setting_length(exec_cfg) + 1)); - - int i; - for (i = 0; i < config_setting_length(exec_cfg); i++) { - const char *elm = config_setting_get_string_elem(exec_cfg, i); - if (!elm) - cerror(exec_cfg, "Invalid format for exec"); - - shm->exec[i] = strdup(elm); + shm->exec[index] = strdup(val); } - shm->exec[i] = NULL; + shm->exec[index] = NULL; } return 0; diff --git a/lib/nodes/signal.c b/lib/nodes/signal.c index e3d11d489..77da72999 100644 --- a/lib/nodes/signal.c +++ b/lib/nodes/signal.c @@ -45,43 +45,46 @@ enum signal_type signal_lookup_type(const char *type) return -1; } -int signal_parse(struct node *n, config_setting_t *cfg) +int signal_parse(struct node *n, json_t *cfg) { struct signal *s = n->_vd; int ret; - const char *type; + const char *type = NULL; - if (!config_setting_lookup_string(cfg, "signal", &type)) - s->type = SIGNAL_TYPE_MIXED; - else { + json_error_t err; + + s->rt = 1; + s->limit = -1; + s->values = 1; + s->rate = 10; + s->frequency = 1; + s->amplitude = 1; + s->stddev = 0.02; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: i, s?: f, s?: f, s?: f, s?: f }", + "signal", &type, + "realtime", &s->rt, + "limit", &s->limit, + "values", &s->values, + "rate", &s->rate, + "frequency", &s->frequency, + "amplitude", &s->amplitude, + "stddev", &s->stddev + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + + + if (type) { ret = signal_lookup_type(type); if (ret == -1) - cerror(cfg, "Unknown signal type '%s'", type); + error("Unknown signal type '%s' of node %s", type, node_name(n)); s->type = ret; } - - if (!config_setting_lookup_bool(cfg, "realtime", &s->rt)) - s->rt = 1; - - if (!config_setting_lookup_int(cfg, "limit", &s->limit)) - s->limit = -1; - - if (!config_setting_lookup_int(cfg, "values", &s->values)) - s->values = 1; - - if (!config_setting_lookup_float(cfg, "rate", &s->rate)) - s->rate = 10; - - if (!config_setting_lookup_float(cfg, "frequency", &s->frequency)) - s->frequency = 1; - - if (!config_setting_lookup_float(cfg, "amplitude", &s->amplitude)) - s->amplitude = 1; - - if (!config_setting_lookup_float(cfg, "stddev", &s->stddev)) - s->stddev = 0.02; + else + s->type = SIGNAL_TYPE_MIXED; return 0; } @@ -226,7 +229,7 @@ int signal_read(struct node *n, struct sample *smps[], unsigned cnt) } if (s->limit > 0 && s->counter >= s->limit) { - info("Reached limit"); + info("Reached limit of node %s", node_name(n)); killme(SIGTERM); pause(); } diff --git a/lib/nodes/socket.c b/lib/nodes/socket.c index f972f7be6..f69f7db52 100644 --- a/lib/nodes/socket.c +++ b/lib/nodes/socket.c @@ -561,18 +561,40 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt) return -1; } -int socket_parse(struct node *n, config_setting_t *cfg) +int socket_parse(struct node *n, json_t *cfg) { - config_setting_t *cfg_multicast; - const char *local, *remote, *layer, *hdr, *endian; - int ret; - struct socket *s = n->_vd; + const char *local, *remote; + const char *endian = NULL; + const char *layer = NULL; + const char *header = NULL; + + int ret; + + json_t *cfg_multicast = NULL; + json_error_t err; + + /* Default values */ + s->layer = SOCKET_LAYER_UDP; + s->header = SOCKET_HEADER_DEFAULT; + s->endian = SOCKET_ENDIAN_BIG; + s->verify_source = 0; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s: s, s: s, s?: b, s?: o }", + "layer", &layer, + "header", &header, + "endian", &endian, + "remote", &remote, + "local", &local, + "verify_source", &s->verify_source, + "multicast", &cfg_multicast + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + /* IP layer */ - if (!config_setting_lookup_string(cfg, "layer", &layer)) - s->layer = SOCKET_LAYER_UDP; - else { + if (layer) { if (!strcmp(layer, "ip")) s->layer = SOCKET_LAYER_IP; #ifdef __linux__ @@ -582,103 +604,89 @@ int socket_parse(struct node *n, config_setting_t *cfg) else if (!strcmp(layer, "udp")) s->layer = SOCKET_LAYER_UDP; else - cerror(cfg, "Invalid layer '%s' for node %s", layer, node_name(n)); + error("Invalid layer '%s' for node %s", layer, node_name(n)); } /* Application header */ - if (!config_setting_lookup_string(cfg, "header", &hdr)) - s->header = SOCKET_HEADER_DEFAULT; - else { - if (!strcmp(hdr, "gtnet-skt") || (!strcmp(hdr, "none"))) + if (header) { + if (!strcmp(header, "gtnet-skt") || (!strcmp(header, "none"))) s->header = SOCKET_HEADER_NONE; - else if (!strcmp(hdr, "gtnet-skt:fake") || (!strcmp(hdr, "fake"))) + else if (!strcmp(header, "gtnet-skt:fake") || (!strcmp(header, "fake"))) s->header = SOCKET_HEADER_FAKE; - else if (!strcmp(hdr, "villas") || !strcmp(hdr, "default")) + else if (!strcmp(header, "villas") || !strcmp(header, "default")) s->header = SOCKET_HEADER_DEFAULT; else - cerror(cfg, "Invalid application header type '%s' for node %s", hdr, node_name(n)); + error("Invalid application header type '%s' for node %s", header, node_name(n)); } - if (!config_setting_lookup_string(cfg, "endian", &endian)) - s->endian = SOCKET_ENDIAN_BIG; - else { + if (endian) { if (!strcmp(endian, "big") || !strcmp(endian, "network")) s->endian = SOCKET_ENDIAN_BIG; else if (!strcmp(endian, "little")) s->endian = SOCKET_ENDIAN_LITTLE; else - cerror(cfg, "Invalid endianness type '%s' for node %s", endian, node_name(n)); + error("Invalid endianness type '%s' for node %s", endian, node_name(n)); } - if (!config_setting_lookup_string(cfg, "remote", &remote)) - cerror(cfg, "Missing remote address for node %s", node_name(n)); - - if (!config_setting_lookup_string(cfg, "local", &local)) - cerror(cfg, "Missing local address for node %s", node_name(n)); - - if (!config_setting_lookup_bool(cfg, "verify_source", &s->verify_source)) - s->verify_source = 0; - ret = socket_parse_addr(local, (struct sockaddr *) &s->local, s->layer, AI_PASSIVE); if (ret) { - cerror(cfg, "Failed to resolve local address '%s' of node %s: %s", + error("Failed to resolve local address '%s' of node %s: %s", local, node_name(n), gai_strerror(ret)); } ret = socket_parse_addr(remote, (struct sockaddr *) &s->remote, s->layer, 0); if (ret) { - cerror(cfg, "Failed to resolve remote address '%s' of node %s: %s", + error("Failed to resolve remote address '%s' of node %s: %s", remote, node_name(n), gai_strerror(ret)); } - cfg_multicast = config_setting_get_member(cfg, "multicast"); if (cfg_multicast) { - const char *group, *interface; + const char *group, *interface = NULL; - if (!config_setting_lookup_bool(cfg_multicast, "enabled", &s->multicast.enabled)) - s->multicast.enabled = true; + /* Default values */ + s->multicast.enabled = true; + s->multicast.mreq.imr_interface.s_addr = INADDR_ANY; + s->multicast.loop = 0; + s->multicast.ttl = 255; - if (!config_setting_lookup_string(cfg_multicast, "group", &group)) - cerror(cfg_multicast, "The multicast group requires a 'group' setting."); - else { - ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr); - if (!ret) { - cerror(cfg_multicast, "Failed to resolve multicast group address '%s' of node %s", - group, node_name(n)); - } + ret = json_unpack_ex(cfg_multicast, &err, 0, "{ s?: b, s: s, s?: s, s?: b, s?: i }", + "enabled", &s->multicast.enabled, + "group", &group, + "interface", &interface, + "loop", &s->multicast.loop, + "ttl", &s->multicast.ttl + ); + if (ret) + jerror(&err, "Failed to parse setting 'multicast' of node %s", node_name(n)); + + ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr); + if (!ret) { + error("Failed to resolve multicast group address '%s' of node %s", + group, node_name(n)); } - if (!config_setting_lookup_string(cfg_multicast, "interface", &interface)) - s->multicast.mreq.imr_interface.s_addr = INADDR_ANY; - else { + if (interface) { ret = inet_aton(group, &s->multicast.mreq.imr_interface); if (!ret) { - cerror(cfg_multicast, "Failed to resolve multicast interface address '%s' of node %s", + error("Failed to resolve multicast interface address '%s' of node %s", interface, node_name(n)); } } - - int loop; - if (!config_setting_lookup_bool(cfg_multicast, "loop", &loop)) - s->multicast.loop = 0; - else - s->multicast.loop = loop; - - int ttl; - if (!config_setting_lookup_int(cfg_multicast, "ttl", &ttl)) - s->multicast.ttl = 255; - else - s->multicast.ttl = ttl; } #ifdef WITH_NETEM - config_setting_t *cfg_netem; + json_t *cfg_netem; - cfg_netem = config_setting_get_member(cfg, "netem"); + cfg_netem = json_object_get(cfg, "netem"); if (cfg_netem) { int enabled = 1; - if (!config_setting_lookup_bool(cfg_netem, "enabled", &enabled) || enabled) - tc_parse(cfg_netem, &s->tc_qdisc); + + ret = json_unpack_ex(cfg_netem, &err, 0, "{ s?: b }", "enabled", &enabled); + if (ret) + jerror(&err, "Failed to parse setting 'netem' of node %s", node_name(n)); + + if (enabled) + tc_parse(&s->tc_qdisc, cfg_netem); else s->tc_qdisc = NULL; } diff --git a/lib/nodes/websocket.c b/lib/nodes/websocket.c index 7240c9beb..6aa153072 100644 --- a/lib/nodes/websocket.c +++ b/lib/nodes/websocket.c @@ -26,8 +26,6 @@ #include #include -#include - #include "super_node.h" #include "webmsg.h" #include "webmsg_format.h" @@ -510,36 +508,41 @@ int websocket_write(struct node *n, struct sample *smps[], unsigned cnt) return cnt; } -int websocket_parse(struct node *n, config_setting_t *cfg) +int websocket_parse(struct node *n, json_t *cfg) { struct websocket *w = n->_vd; - config_setting_t *cfg_dests; int ret; + size_t index; + json_t *cfg_dests = NULL; + json_t *cfg_dest; + json_error_t err; + list_init(&w->connections); list_init(&w->destinations); - cfg_dests = config_setting_get_member(cfg, "destinations"); - if (cfg_dests) { - if (!config_setting_is_array(cfg_dests)) - cerror(cfg_dests, "The 'destinations' setting must be an array of URLs"); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "destinations", &cfg_dests); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); - for (int i = 0; i < config_setting_length(cfg_dests); i++) { + if (cfg_dests) { + if (!json_is_array(cfg_dests)) + error("The 'destinations' setting of node %s must be an array of URLs", node_name(n)); + + json_array_foreach(cfg_dests, index, cfg_dest) { const char *uri, *prot, *ads, *path; - uri = config_setting_get_string_elem(cfg_dests, i); + uri = json_string_value(cfg_dest); if (!uri) - cerror(cfg_dests, "The 'destinations' setting must be an array of URLs"); + error("The 'destinations' setting of node %s must be an array of URLs", node_name(n)); struct websocket_destination *d = alloc(sizeof(struct websocket_destination)); d->uri = strdup(uri); - if (!d->uri) - serror("Failed to allocate memory"); ret = lws_parse_uri(d->uri, &prot, &ads, &d->info.port, &path); if (ret) - cerror(cfg_dests, "Failed to parse websocket URI: '%s'", uri); + error("Failed to parse WebSocket URI: '%s'", uri); d->info.ssl_connection = !strcmp(prot, "https"); d->info.address = strdup(ads); diff --git a/lib/nodes/zeromq.c b/lib/nodes/zeromq.c index 9f49b42a3..0b84fe479 100644 --- a/lib/nodes/zeromq.c +++ b/lib/nodes/zeromq.c @@ -89,83 +89,92 @@ int zeromq_reverse(struct node *n) return 0; } -int zeromq_parse(struct node *n, config_setting_t *cfg) +int zeromq_parse(struct node *n, json_t *cfg) { struct zeromq *z = n->_vd; - const char *ep, *type, *filter; + int ret; + const char *ep = NULL; + const char *type = NULL; + const char *filter = NULL; - config_setting_t *cfg_pub, *cfg_curve; + size_t index; + json_t *cfg_pub = NULL; + json_t *cfg_curve = NULL; + json_t *cfg_val; + json_error_t err; list_init(&z->publisher.endpoints); - if (config_setting_lookup_string(cfg, "subscribe", &ep)) - z->subscriber.endpoint = strdup(ep); - else - z->subscriber.endpoint = NULL; + z->curve.enabled = false; + z->ipv6 = 0; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: o, s?: o, s?: s, s?: s, s?: b }", + "subscribe", &ep, + "publish", &cfg_pub, + "curve", &cfg_curve, + "filter", &filter, + "pattern", &type, + "ipv6", &z->ipv6 + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + + z->subscriber.endpoint = ep ? strdup(ep) : NULL; + z->filter = filter ? strdup(filter) : NULL; - cfg_pub = config_setting_lookup(cfg, "publish"); if (cfg_pub) { - switch (config_setting_type(cfg_pub)) { - case CONFIG_TYPE_LIST: - case CONFIG_TYPE_ARRAY: - for (int j = 0; j < config_setting_length(cfg_pub); j++) { - const char *ep = config_setting_get_string_elem(cfg_pub, j); + switch (json_typeof(cfg_pub)) { + case JSON_ARRAY: + json_array_foreach(cfg_pub, index, cfg_val) { + ep = json_string_value(cfg_pub); + if (!ep) + error("All 'publish' settings must be strings"); list_push(&z->publisher.endpoints, strdup(ep)); } break; - case CONFIG_TYPE_STRING: - ep = config_setting_get_string(cfg_pub); + case JSON_STRING: + ep = json_string_value(cfg_pub); list_push(&z->publisher.endpoints, strdup(ep)); break; default: - cerror(cfg_pub, "Invalid type for ZeroMQ publisher setting"); + error("Invalid type for ZeroMQ publisher setting"); } } - cfg_curve = config_setting_lookup(cfg, "curve"); if (cfg_curve) { - if (!config_setting_is_group(cfg_curve)) - cerror(cfg_curve, "The curve setting must be a group"); - const char *public_key, *secret_key; - if (!config_setting_lookup_string(cfg_curve, "public_key", &public_key)) - cerror(cfg_curve, "Setting 'curve.public_key' is missing"); + z->curve.enabled = true; - if (!config_setting_lookup_string(cfg_curve, "secret_key", &secret_key)) - cerror(cfg_curve, "Setting 'curve.secret_key' is missing"); - - if (!config_setting_lookup_bool(cfg_curve, "enabled", &z->curve.enabled)) - z->curve.enabled = true; + ret = json_unpack_ex(cfg_curve, &err, 0, "{ s: s, s: s, s?: b }", + "public_key", &public_key, + "secret_key", &secret_key, + "enabled", &z->curve.enabled + ); + if (ret) + jerror(&err, "Failed to parse setting 'curve' of node %s", node_name(n)); if (strlen(secret_key) != 40) - cerror(cfg_curve, "Setting 'curve.secret_key' must be a Z85 encoded CurveZMQ key"); + error("Setting 'curve.secret_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n)); if (strlen(public_key) != 40) - cerror(cfg_curve, "Setting 'curve.public_key' must be a Z85 encoded CurveZMQ key"); + error("Setting 'curve.public_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n)); strncpy(z->curve.server.public_key, public_key, 41); strncpy(z->curve.server.secret_key, secret_key, 41); } - else - z->curve.enabled = false; /** @todo We should fix this. Its mostly done. */ if (z->curve.enabled) - cerror(cfg_curve, "CurveZMQ support is currently broken"); + error("CurveZMQ support is currently broken"); - if (config_setting_lookup_string(cfg, "filter", &filter)) - z->filter = strdup(filter); - else - z->filter = NULL; - - if (config_setting_lookup_string(cfg, "pattern", &type)) { + if (type) { if (!strcmp(type, "pubsub")) z->pattern = ZEROMQ_PATTERN_PUBSUB; #ifdef ZMQ_BUILD_DISH @@ -173,12 +182,9 @@ int zeromq_parse(struct node *n, config_setting_t *cfg) z->pattern = ZEROMQ_PATTERN_RADIODISH; #endif else - cerror(cfg, "Invalid type for ZeroMQ node: %s", node_name_short(n)); + error("Invalid type for ZeroMQ node: %s", node_name_short(n)); } - if (!config_setting_lookup_bool(cfg, "ipv6", &z->ipv6)) - z->ipv6 = 0; - return 0; } diff --git a/lib/path.c b/lib/path.c index 457612288..52301767c 100644 --- a/lib/path.c +++ b/lib/path.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "config.h" #include "utils.h" @@ -39,6 +38,7 @@ #include "memory.h" #include "stats.h" #include "node.h" +#include "config_helper.h" static void path_read(struct path *p) { @@ -180,46 +180,51 @@ int path_init(struct path *p, struct super_node *sn) return 0; } -int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes) +int path_parse(struct path *p, json_t *cfg, struct list *nodes) { - config_setting_t *cfg_out, *cfg_hooks; - const char *in; int ret; + const char *in; + + json_error_t err; + json_t *cfg_out = NULL; + json_t *cfg_hooks = NULL; struct node *source; struct list destinations = { .state = STATE_DESTROYED }; list_init(&destinations); - /* Input node */ - if (!config_setting_lookup_string(cfg, "in", &in)) - cerror(cfg, "Missing input node for path"); + ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: o, s?: o, s?: b, s?: b, s?: i, s?: i }", + "in", &in, + "out", &cfg_out, + "hooks", &cfg_hooks, + "reverse", &p->reverse, + "enabled", &p->enabled, + "samplelen", &p->samplelen, + "queuelen", &p->queuelen + ); + if (ret) + jerror(&err, "Failed to parse path configuration"); + /* Input node */ source = list_lookup(nodes, in); if (!source) - cerror(cfg, "Invalid input node '%s'", in); + jerror(&err, "Invalid input node '%s'", in); /* Output node(s) */ - cfg_out = config_setting_get_member(cfg, "out"); if (cfg_out) { ret = node_parse_list(&destinations, cfg_out, nodes); if (ret) - cerror(cfg_out, "Failed to parse output nodes"); + jerror(&err, "Failed to parse output nodes"); } /* Optional settings */ - cfg_hooks = config_setting_get_member(cfg, "hooks"); if (cfg_hooks) { ret = hook_parse_list(&p->hooks, cfg_hooks, p); if (ret) return ret; } - config_setting_lookup_bool(cfg, "reverse", &p->reverse); - config_setting_lookup_bool(cfg, "enabled", &p->enabled); - config_setting_lookup_int(cfg, "samplelen", &p->samplelen); - config_setting_lookup_int(cfg, "queuelen", &p->queuelen); - if (!IS_POW2(p->queuelen)) { p->queuelen = LOG2_CEIL(p->queuelen); warn("Queue length should always be a power of 2. Adjusting to %d", p->queuelen); @@ -242,6 +247,9 @@ int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes) list_destroy(&destinations, NULL, false); + p->cfg = cfg; + p->state = STATE_PARSED; + return 0; } diff --git a/lib/plugin.c b/lib/plugin.c index 5bd37292e..7652b089d 100644 --- a/lib/plugin.c +++ b/lib/plugin.c @@ -23,6 +23,7 @@ #include #include "plugin.h" +#include "config_helper.h" /** Global list of all known plugins */ struct list plugins = { .state = STATE_DESTROYED }; @@ -38,13 +39,15 @@ int plugin_init(struct plugin *p) return 0; } -int plugin_parse(struct plugin *p, config_setting_t *cfg) +int plugin_parse(struct plugin *p, json_t *cfg) { const char *path; - path = config_setting_get_string(cfg); + path = json_string_value(cfg); if (!path) - cerror(cfg, "Setting 'plugin' must be a string."); + return -1; + + p->path = strdup(path); return 0; } diff --git a/lib/stats.c b/lib/stats.c index ea156d26a..194fc5dc1 100644 --- a/lib/stats.c +++ b/lib/stats.c @@ -124,7 +124,6 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt) s->last = previous; } -#ifdef WITH_JSON json_t * stats_json(struct stats *s) { json_t *obj = json_object(); @@ -150,7 +149,6 @@ json_t * stats_json_periodic(struct stats *s, struct path *p) "skipped", s->histograms[STATS_SKIPPED].total ); } -#endif /* WITH_JSON */ void stats_reset(struct stats *s) { @@ -209,13 +207,11 @@ void stats_print_periodic(struct stats *s, FILE *f, enum stats_format fmt, int v ); break; -#ifdef WITH_JSON case STATS_FORMAT_JSON: { json_t *json_stats = stats_json_periodic(s, p); json_dumpf(json_stats, f, 0); break; } -#endif /* WITH_JSON */ default: { } } @@ -233,14 +229,12 @@ void stats_print(struct stats *s, FILE *f, enum stats_format fmt, int verbose) } break; -#ifdef WITH_JSON case STATS_FORMAT_JSON: { json_t *json_stats = stats_json(s); json_dumpf(json_stats, f, 0); fflush(f); break; } -#endif /* WITH_JSON */ default: { } } diff --git a/lib/super_node.c b/lib/super_node.c index be26114d3..bc80d9c7a 100644 --- a/lib/super_node.c +++ b/lib/super_node.c @@ -1,4 +1,4 @@ -/** Configuration parser. +/** The super node object holding the state of the application. * * @author Steffen Vogel * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC @@ -42,30 +42,10 @@ #include "kernel/rt.h" -static void config_dtor(void *data) -{ - if (data) - free(data); -} - -static int super_node_parse_global(struct super_node *sn, config_setting_t *cfg) -{ - if (!config_setting_is_group(cfg)) - cerror(cfg, "Global section must be a dictionary."); - - config_setting_lookup_int(cfg, "hugepages", &sn->hugepages); - config_setting_lookup_int(cfg, "affinity", &sn->affinity); - config_setting_lookup_int(cfg, "priority", &sn->priority); - config_setting_lookup_float(cfg, "stats", &sn->stats); - - return 0; -} - int super_node_init(struct super_node *sn) { assert(sn->state == STATE_DESTROYED); - log_init(&sn->log, V, LOG_ALL); #ifdef WITH_API api_init(&sn->api, sn); #endif /* WITH_API */ @@ -83,6 +63,9 @@ int super_node_init(struct super_node *sn) sn->stats = 0; sn->hugepages = DEFAULT_NR_HUGEPAGES; + sn->name = alloc(128); /** @todo missing free */ + gethostname(sn->name, 128); + sn->state = STATE_INITIALIZED; return 0; @@ -90,85 +73,81 @@ int super_node_init(struct super_node *sn) int super_node_parse_uri(struct super_node *sn, const char *uri) { - int ret = CONFIG_FALSE; + json_error_t err; if (uri) { INDENT FILE *f; AFILE *af; - config_setting_t *cfg_root = NULL; /* Via stdin */ if (!strcmp("-", uri)) { + info("Reading configuration from stdin"); + af = NULL; f = stdin; - - info("Reading configuration from stdin"); } else { - /* Local file? */ - if (access(uri, F_OK) != -1) { - /* Setup libconfig include path. - * This is only supported for local files */ - char *uri_cpy = strdup(uri); - char *include_dir = dirname(uri_cpy); - - config_set_include_dir(&sn->cfg, include_dir); - - free(uri_cpy); - - info("Reading configuration from local file: %s", uri); - } - else - info("Reading configuration from URI: %s", uri); + info("Reading configuration from URI: %s", uri); af = afopen(uri, "r"); - f = af ? af->file : NULL; + if (!af) + error("Failed to open configuration from: %s", uri); + + f = af->file; } - /* Check if file could be loaded / opened */ - if (!f) - error("Failed to open configuration"); - - config_init(&sn->cfg); - config_set_destructor(&sn->cfg, config_dtor); - config_set_auto_convert(&sn->cfg, 1); - /* Parse config */ - ret = config_read(&sn->cfg, f); - if (ret != CONFIG_TRUE) { -#ifdef WITH_JSON - /* This does not seem to be a valid libconfig configuration. - * Lets try to parse it as JSON instead. */ - json_error_t err; - json_t *json; + sn->cfg = json_loadf(f, 0, &err); + if (sn->cfg == NULL) { +#ifdef WITH_LIBCONFIG + int ret; - json = json_loadf(f, 0, &err); - if (json) { - ret = json_to_config(json, cfg_root); - if (ret) - error("Failed t convert JSON to configuration file"); + config_t cfg; + config_setting_t *cfg_root = NULL; + + warn("Failed to parse JSON configuration. Re-trying with old libconfig format."); + { INDENT + warn("Please consider migrating to the new format using the 'conf2json' command."); } - else { - error("Failed to parse configuration"); + + config_init(&cfg); + config_set_auto_convert(&cfg, 1); + + /* Setup libconfig include path. + * This is only supported for local files */ + if (access(uri, F_OK) != -1) { + char *cpy = strdup(uri); + + config_set_include_dir(&cfg, dirname(cpy)); + + free(cpy); + } + + if (af) + arewind(af); + else + rewind(f); + + ret = config_read(&cfg, f); + if (ret != CONFIG_TRUE) { { INDENT - warn("conf: %s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg)); + warn("conf: %s in %s:%d", config_error_text(&cfg), uri, config_error_line(&cfg)); warn("json: %s in %s:%d:%d", err.text, err.source, err.line, err.column); } + error("Failed to parse configuration"); } -#else - error("Failed to parse configuration"); - { INDENT - warn("%s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg)); - } -#endif - } - /* Little hack to properly report configuration filename in error messages - * We add the uri as a "hook" object to the root setting. - * See cerror() on how this info is used. - */ - cfg_root = config_root_setting(&sn->cfg); - config_setting_set_hook(cfg_root, strdup(uri)); + cfg_root = config_root_setting(&cfg); + + sn->cfg = config_to_json(cfg_root); + if (sn->cfg == NULL) + error("Failed to convert JSON to configuration file"); + + config_destroy(&cfg); +#else + jerror(&err, "Failed to parse configuration file"); +#endif /* WITH_LIBCONFIG */ + } /* Close configuration file */ if (af) @@ -176,11 +155,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri) else if (f != stdin) fclose(f); - ret = super_node_parse(sn, cfg_root); - - config_destroy(&sn->cfg); - - return ret; + return super_node_parse_json(sn, sn->cfg); } else { INDENT warn("No configuration file specified. Starting unconfigured. Use the API to configure this instance."); @@ -199,105 +174,120 @@ int super_node_parse_cli(struct super_node *sn, int argc, char *argv[]) return super_node_parse_uri(sn, uri); } -int super_node_parse(struct super_node *sn, config_setting_t *cfg) +int super_node_parse_json(struct super_node *sn, json_t *cfg) { int ret; + const char *name = NULL; assert(sn->state != STATE_STARTED); assert(sn->state != STATE_DESTROYED); - config_setting_t *cfg_nodes, *cfg_paths, *cfg_plugins, *cfg_logging; + json_t *cfg_nodes = NULL; + json_t *cfg_paths = NULL; + json_t *cfg_plugins = NULL; + json_t *cfg_logging = NULL; + json_t *cfg_web = NULL; - super_node_parse_global(sn, cfg); + json_error_t err; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o, s?: o, s?: o, s?: o, s?: i, s?: i, s?: i, s?: F, s?: s }", + "http", &cfg_web, + "logging", &cfg_logging, + "plugins", &cfg_plugins, + "nodes", &cfg_nodes, + "paths", &cfg_paths, + "hugepages", &sn->hugepages, + "affinity", &sn->affinity, + "priority", &sn->priority, + "stats", &sn->stats, + "name", &name + ); + if (ret) + jerror(&err, "Failed to parse global configuration"); + + if (name) + strncpy(sn->name, name, 128); #ifdef WITH_WEB - config_setting_t *cfg_web; - - cfg_web = config_setting_get_member(cfg, "http"); if (cfg_web) web_parse(&sn->web, cfg_web); #endif /* WITH_WEB */ - /* Parse logging settings */ - cfg_logging = config_setting_get_member(cfg, "logging"); if (cfg_logging) log_parse(&sn->log, cfg_logging); /* Parse plugins */ - cfg_plugins = config_setting_get_member(cfg, "plugins"); if (cfg_plugins) { - if (!config_setting_is_array(cfg_plugins)) - cerror(cfg_plugins, "Setting 'plugins' must be a list of strings"); - - for (int i = 0; i < config_setting_length(cfg_plugins); i++) { - struct config_setting_t *cfg_plugin = config_setting_get_elem(cfg_plugins, i); + if (!json_is_array(cfg_plugins)) + error("Setting 'plugins' must be a list of strings"); + size_t index; + json_t *cfg_plugin; + json_array_foreach(cfg_plugins, index, cfg_plugin) { struct plugin *p = alloc(sizeof(struct plugin)); ret = plugin_init(p); if (ret) - cerror(cfg_plugin, "Failed to initialize plugin"); + error("Failed to initialize plugin"); ret = plugin_parse(p, cfg_plugin); if (ret) - cerror(cfg_plugin, "Failed to parse plugin"); + error("Failed to parse plugin"); list_push(&sn->plugins, p); } } /* Parse nodes */ - cfg_nodes = config_setting_get_member(cfg, "nodes"); if (cfg_nodes) { - if (!config_setting_is_group(cfg_nodes)) - warn("Setting 'nodes' must be a group with node name => group mappings."); - - for (int i = 0; i < config_setting_length(cfg_nodes); i++) { - config_setting_t *cfg_node = config_setting_get_elem(cfg_nodes, i); + if (!json_is_object(cfg_nodes)) + error("Setting 'nodes' must be a group with node name => group mappings."); + const char *name; + json_t *cfg_node; + json_object_foreach(cfg_nodes, name, cfg_node) { struct plugin *p; const char *type; - /* Required settings */ - if (!config_setting_lookup_string(cfg_node, "type", &type)) - cerror(cfg_node, "Missing node type"); + ret = json_unpack_ex(cfg_node, &err, 0, "{ s: s }", "type", &type); + if (ret) + jerror(&err, "Failed to parse node"); p = plugin_lookup(PLUGIN_TYPE_NODE, type); if (!p) - cerror(cfg_node, "Invalid node type: %s", type); + error("Invalid node type: %s", type); struct node *n = alloc(sizeof(struct node)); ret = node_init(n, &p->node); if (ret) - cerror(cfg_node, "Failed to initialize node"); + error("Failed to initialize node"); - ret = node_parse(n, cfg_node); + ret = node_parse(n, cfg_node, name); if (ret) - cerror(cfg_node, "Failed to parse node"); + error("Failed to parse node"); list_push(&sn->nodes, n); } } /* Parse paths */ - cfg_paths = config_setting_get_member(cfg, "paths"); if (cfg_paths) { - if (!config_setting_is_list(cfg_paths)) + if (!json_is_array(cfg_paths)) warn("Setting 'paths' must be a list."); - for (int i = 0; i < config_setting_length(cfg_paths); i++) { - config_setting_t *cfg_path = config_setting_get_elem(cfg_paths, i); - + size_t index; + json_t *cfg_path; + json_array_foreach(cfg_paths, index, cfg_path) { struct path *p = alloc(sizeof(struct path)); ret = path_init(p, sn); if (ret) - cerror(cfg_path, "Failed to init path"); + error("Failed to initialize path"); ret = path_parse(p, cfg_path, &sn->nodes); if (ret) - cerror(cfg_path, "Failed to parse path"); + error("Failed to parse path"); list_push(&sn->paths, p); @@ -306,11 +296,11 @@ int super_node_parse(struct super_node *sn, config_setting_t *cfg) ret = path_init(r, sn); if (ret) - cerror(cfg_path, "Failed to init path"); + error("Failed to init path"); ret = path_reverse(p, r); if (ret) - cerror(cfg_path, "Failed to reverse path %s", path_name(p)); + error("Failed to reverse path %s", path_name(p)); list_push(&sn->paths, r); } @@ -455,12 +445,17 @@ int super_node_destroy(struct super_node *sn) #ifdef WITH_WEB web_destroy(&sn->web); -#endif +#endif /* WITH_WEB */ #ifdef WITH_API api_destroy(&sn->api); -#endif +#endif /* WITH_API */ + + json_decref(sn->cfg); log_destroy(&sn->log); + if (sn->name) + free(sn->name); + sn->state = STATE_DESTROYED; return 0; diff --git a/lib/web.c b/lib/web.c index 6384d683d..d0dfa02e4 100644 --- a/lib/web.c +++ b/lib/web.c @@ -20,7 +20,6 @@ * along with this program. If not, see . *********************************************************************************/ -#include #include #include @@ -28,6 +27,7 @@ #include "log.h" #include "web.h" #include "api/session.h" +#include "config_helper.h" #include "nodes/websocket.h" @@ -168,30 +168,37 @@ int web_init(struct web *w, struct api *a) return 0; } -int web_parse(struct web *w, config_setting_t *cfg) +int web_parse(struct web *w, json_t *cfg) { - int enabled = true; - const char *ssl_cert, *ssl_private_key, *htdocs; + int ret, enabled = 1; + const char *ssl_cert = NULL; + const char *ssl_private_key = NULL; + const char *htdocs = NULL; + json_error_t err; - if (!config_setting_is_group(cfg)) - cerror(cfg, "Setting 'http' must be a group."); + ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s?: i, s?: b }", + "ssl_cert", &ssl_cert, + "ssl_private_key", &ssl_private_key, + "htdocs", &htdocs, + "port", &w->port, + "enabled", &enabled + ); + if (ret) + jerror(&err, "Failed to http section of configuration file"); - if (config_setting_lookup_string(cfg, "ssl_cert", &ssl_cert)) + if (ssl_cert) w->ssl_cert = strdup(ssl_cert); - if (config_setting_lookup_string(cfg, "ssl_private_key", &ssl_private_key)) + if (ssl_private_key) w->ssl_private_key = strdup(ssl_private_key); - if (config_setting_lookup_string(cfg, "htdocs", &htdocs)) { + if (htdocs) { if (w->htdocs) free(w->htdocs); w->htdocs = strdup(htdocs); } - config_setting_lookup_int(cfg, "port", &w->port); - config_setting_lookup_bool(cfg, "enabled", &enabled); - if (!enabled) w->port = CONTEXT_PORT_NO_LISTEN; @@ -247,7 +254,7 @@ int web_start(struct web *w) int web_stop(struct web *w) { - if (w->state == STATE_STARTED) + if (w->state != STATE_STARTED) return 0; info("Stopping Web sub-system"); diff --git a/lib/web/buffer.c b/lib/web/buffer.c index e6e8807d6..c45912956 100644 --- a/lib/web/buffer.c +++ b/lib/web/buffer.c @@ -98,7 +98,6 @@ int web_buffer_read(struct web_buffer *b, char *out, size_t len) return 0; } -#ifdef WITH_JSON int web_buffer_read_json(struct web_buffer *b, json_t **req) { json_error_t e; @@ -116,7 +115,6 @@ int web_buffer_read_json(struct web_buffer *b, json_t **req) return 1; } -#endif /* WITH_JSON */ int web_buffer_append(struct web_buffer *b, const char *in, size_t len) { @@ -140,7 +138,6 @@ int web_buffer_append(struct web_buffer *b, const char *in, size_t len) return 0; } -#ifdef WITH_JSON int web_buffer_append_json(struct web_buffer *b, json_t *res) { size_t len; @@ -162,4 +159,3 @@ retry: len = json_dumpb(res, b->buffer + b->prefix + b->len, b->size - b->len, 0 return 0; } -#endif /* WITH_JSON */ diff --git a/src/hook.c b/src/hook.c index d2d35fbea..1dfaf2812 100644 --- a/src/hook.c +++ b/src/hook.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -103,20 +104,34 @@ int main(int argc, char *argv[]) /* Default values */ cnt = 1; - char c; - while ((c = getopt(argc, argv, "hv:d:")) != -1) { + json_t *cfg_cli = json_object(); + + char c, *endptr; + while ((c = getopt(argc, argv, "hv:d:f:o:")) != -1) { switch (c) { + break; case 'v': - cnt = atoi(optarg); - break; + cnt = strtoul(optarg, &endptr, 0); + goto check; case 'd': - l.level = atoi(optarg); + l.level = strtoul(optarg, &endptr, 0); + goto check; + case 'o': + ret = json_object_extend_str(cfg_cli, optarg); + if (ret) + error("Invalid option: %s", optarg); break; - case 'h': case '?': + case 'h': usage(); exit(c == '?' ? EXIT_FAILURE : EXIT_SUCCESS); } + + continue; + +check: if (optarg == endptr) + error("Failed to parse parse option argument '-%c %s'", c, optarg); + } if (argc < optind + 1) { @@ -156,7 +171,7 @@ int main(int argc, char *argv[]) if (ret) error("Failed to initialize hook"); - ret = hook_parse_cli(&h, argc - optind - 1, &argv[optind + 1]); + ret = hook_parse(&h, cfg_cli); if (ret) error("Failed to parse hook config"); diff --git a/src/pipe.c b/src/pipe.c index c00726032..a8acb8251 100644 --- a/src/pipe.c +++ b/src/pipe.c @@ -33,11 +33,11 @@ #include #include #include -#include #include #include #include #include +#include #include diff --git a/tests/unit/config_json.c b/tests/unit/config_json.c index 8f372eb33..d1b86c6f7 100644 --- a/tests/unit/config_json.c +++ b/tests/unit/config_json.c @@ -22,6 +22,8 @@ #include +#ifdef WITH_LIBCONFIG + #include #include @@ -114,3 +116,5 @@ Test(utils, json_to_config) json_decref(json); } + +#endif diff --git a/tests/unit/fpga.c b/tests/unit/fpga.c index 1cd93b3ad..a7703eec3 100644 --- a/tests/unit/fpga.c +++ b/tests/unit/fpga.c @@ -40,7 +40,6 @@ static struct vfio_container vc; static void init() { int ret; - config_setting_t *cfg_root; ret = super_node_init(&sn); cr_assert_eq(ret, 0, "Failed to initialize Supernode"); @@ -51,9 +50,6 @@ static void init() ret = super_node_check(&sn); cr_assert_eq(ret, 0, "Failed to check configuration"); - cfg_root = config_root_setting(&sn.cfg); - cr_assert_neq(cfg_root, NULL); - ret = pci_init(&pci); cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system"); @@ -62,7 +58,7 @@ static void init() /* Parse FPGA configuration */ list_init(&cards); - ret = fpga_card_parse_list(&cards, cfg_root); + ret = fpga_card_parse_list(&cards, sn.cfg); cr_assert_eq(ret, 0, "Failed to parse FPGA config"); card = list_lookup(&cards, "vc707"); @@ -120,7 +116,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add") double factor, err = 0; struct fpga_ip *ip, *dma; - struct model_param *p; + struct model_parameter *p; struct dma_mem mem; ip = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { NULL, "sysgen", "xsg_multiply", NULL }); @@ -135,7 +131,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add") if (!p) error("Missing parameter 'factor' for model '%s'", ip->name); - ret = model_param_read(p, &factor); + ret = model_parameter_read(p, &factor); cr_assert_eq(ret, 0, "Failed to read parameter 'factor' from model '%s'", ip->name); info("Model param: factor = %f", factor); diff --git a/tests/unit/json.c b/tests/unit/json.c new file mode 100644 index 000000000..aaf51fd5b --- /dev/null +++ b/tests/unit/json.c @@ -0,0 +1,99 @@ +/** Unit tests for libjansson helpers + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + + +#include +#include + +#include "config_helper.h" +#include "utils.h" + +struct param { + const char *desc; + const char *json; + char *argv[32]; +}; + +ParameterizedTestParameters(json, json_load_cli) +{ + static struct param params[] = { + // Combined long option + { + .argv = { "dummy", "--option=value", NULL }, + .json = "{ \"option\" : \"value\" }" + }, + // Separated long option + { + .argv = { "dummy", "--option", "value", NULL }, + .json = "{ \"option\" : \"value\" }" + }, + // All kinds of data types + { + .argv = { "dummy", "--integer", "1", "--real", "1.1", "--bool", "true", "--null", "null", "--string", "hello world", NULL }, + .json = "{ \"integer\" : 1, \"real\" : 1.1, \"bool\" : true, \"null\" : null, \"string\" : \"hello world\" }" + }, + // Array generation + { + .argv = { "dummy", "--bool", "true", "--bool", "false", NULL }, + .json = "{ \"bool\" : [ true, false ] }" + }, + // Dots in the option name generate sub objects + { + .argv = { "dummy", "--sub.option", "value", NULL }, + .json = "{ \"sub\" : { \"option\" : \"value\" } }" + }, + // Nesting is possible + { + .argv = { "dummy", "--sub.sub.option", "value", NULL }, + .json = "{ \"sub\" : { \"sub\" : { \"option\" : \"value\" } } }" + }, + // Multiple subgroups are merged + { + .argv = { "dummy", "--sub.sub.option", "value1", "--sub.option", "value2", NULL }, + .json = "{ \"sub\" : { \"option\" : \"value2\", \"sub\" : { \"option\" : \"value1\" } } }" + } + }; + + return cr_make_param_array(struct param, params, ARRAY_LEN(params)); +} + +ParameterizedTest(struct param *p, json, json_load_cli) +{ + json_error_t err; + json_t *json, *cli; + + /* Calculate argc */ + int argc = 0; + while (p->argv[argc]) + argc++; + + json = json_loads(p->json, 0, &err); + cr_assert_not_null(json); + + cli = json_load_cli(argc, p->argv); + cr_assert_not_null(cli); + + //json_dumpf(json, stdout, JSON_INDENT(2)); putc('\n', stdout); + //json_dumpf(cli, stdout, JSON_INDENT(2)); putc('\n', stdout); + + cr_assert(json_equal(json, cli)); +}