From e2f6989fe81c5bf1f42a290082f6919d8667ed76 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Thu, 29 Nov 2012 09:24:02 +1030 Subject: [PATCH] Improve new config prototype code Rework ARRAYs, replacing label string with typed key, declaring KEY and VALUE independently. Implement dna.helper.argv array using key of type unsigned short. Implement mdp.iftype..tick_ms using key of type short for the interface type code. --- config.h | 143 +++++++++++++++++++++++++---------------- config_schema.h | 112 +++++++++++++++++++++----------- config_test.c | 168 +++++++++++++++++++++--------------------------- 3 files changed, 236 insertions(+), 187 deletions(-) diff --git a/config.h b/config.h index 556387f3..faadca0e 100644 --- a/config.h +++ b/config.h @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. /* This file defines the internal API to the configuration file. See "config_schema.h" for the * definition of the configuration schema, which is used to generate these API components. * - * Each STRUCT(NAME, ...) schema declaration produces the following data declaration: + * Each STRUCT(NAME, ...) schema declaration generates the following data declaration: * * struct config_NAME { * ... @@ -47,35 +47,43 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * struct config_NAME bar; * - * Each ARRAY_*(NAME, SIZE, LABELLEN, TYPE, ...) schema declaration produces the following data + * Each ARRAY(NAME, ...) ... END_ARRAY(SIZE) schema declaration produces the following data * declaration: * * struct config_NAME { * unsigned ac; * struct config_NAME__element { - * char label[LABELLEN+1]; - * TYPE value; + * KEY-DECLARATION; + * VALUE-DECLARATION; * } av[SIZE]; * }; * - * A C struct definition containing a count 'ac' of the number of array elements [0..SIZE-1] - * and 'av' an array of element values, each one consisting of a label and the value itself, - * whose TYPE depends on the ARRAY_* declaration itself: + * A C struct definition containing a count 'ac' of the number of array elements 0..SIZE-1, + * and 'av' an array of element values, each one consisting of a key and a value: + * + * KEY_ATOM(TYPE, ...) + * + * TYPE key; * - * ARRAY_ATOM(NAME, SIZE, LABELLEN, TYPE, ...) - * ARRAY_NODE(NAME, SIZE, LABELLEN, TYPE, ...) + * KEY_STRING(SIZE, ...) + * + * char key[SIZE+1]; + * + * VALUE_ATOM(NAME, SIZE, LABELLEN, TYPE, ...) + * VALUE_NODE(NAME, SIZE, LABELLEN, TYPE, ...) * * TYPE value; * - * ARRAY_STRING(NAME, SIZE, LABELLEN, STRINGSIZE, ...) + * VALUE_STRING(STRINGSIZE, ...) * - * char value[STRINGSIZE]; + * char value[STRINGSIZE+1]; * - * ARRAY_STRUCT(NAME, SIZE, LABELLEN, STRUCTNAME, ...) + * VALUE_SUB_STRUCT(STRUCTNAME) + * VALUE_NODE_STRUCT(STRUCTNAME, ...) * * struct config_STRUCTNAME value; * - * Each STRUCT(NAME, ...) and ARRAY_*(NAME, ...) schema declaration produces the following API + * Each STRUCT(NAME, ...) and ARRAY(NAME, ...) schema declaration generates the following API * functions: * * - int dfl_config_NAME(struct config_NAME *dest); @@ -90,8 +98,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * function is used to parse each individual array element, and the parsed result is only * appended to the array if it returns CFOK. * - * If a STRUCT(NAME, VALIDATOR) or ARRAY(NAME, ..., VALIDATOR) schema declaration is given a validator - * function, then the function must have the following signature: + * If a STRUCT(NAME, VALIDATOR) or ARRAY(NAME, VALIDATOR) schema declaration is given a + * validator function, then the function must have the following signature: * * - int VALIDATOR(struct config_NAME *dest, int orig_result); * @@ -206,18 +214,27 @@ struct pattern_list { struct config_##__name __element; #define END_STRUCT \ }; -#define __ARRAY(__name, __size, __lbllen, __decl) \ +#define ARRAY(__name, __validator...) \ struct config_##__name { \ unsigned ac; \ - struct config_##__name##__element { \ - char label[(__lbllen)+1]; \ - __decl; \ + struct config_##__name##__element { +#define KEY_ATOM(__type, __eltparser) \ + __type key; +#define KEY_STRING(__strsize, __eltparser) \ + char key[(__strsize) + 1]; +#define VALUE_ATOM(__type, __eltparser) \ + __type value; +#define VALUE_STRING(__strsize, __eltparser) \ + char value[(__strsize) + 1]; +#define VALUE_NODE(__type, __eltparser) \ + __type value; +#define VALUE_SUB_STRUCT(__structname) \ + struct config_##__structname value; +#define VALUE_NODE_STRUCT(__structname, __eltparser) \ + struct config_##__structname value; +#define END_ARRAY(__size) \ } av[(__size)]; \ }; -#define ARRAY_ATOM(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, __lbllen, __type value) -#define ARRAY_STRING(__name, __size, __lbllen, __strsize, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, __lbllen, char value[(__strsize) + 1]) -#define ARRAY_NODE(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, __lbllen, __type value) -#define ARRAY_STRUCT(__name, __size, __lbllen, __structname, __lblparser, __validator...) __ARRAY(__name, __size, __lbllen, struct config_##__structname value) #include "config_schema.h" #undef STRUCT #undef NODE @@ -226,11 +243,15 @@ struct pattern_list { #undef SUB_STRUCT #undef NODE_STRUCT #undef END_STRUCT -#undef __ARRAY -#undef ARRAY_ATOM -#undef ARRAY_STRING -#undef ARRAY_NODE -#undef ARRAY_STRUCT +#undef ARRAY +#undef KEY_ATOM +#undef KEY_STRING +#undef VALUE_ATOM +#undef VALUE_STRING +#undef VALUE_NODE +#undef VALUE_SUB_STRUCT +#undef VALUE_NODE_STRUCT +#undef END_ARRAY /* Return bit flags for schema default dfl_ and parsing opt_ functions. */ @@ -266,15 +287,19 @@ strbuf strbuf_cf_flags(strbuf, int); #define END_STRUCT \ return CFOK; \ } -#define __ARRAY(__name) \ +#define ARRAY(__name, __validator...) \ int dfl_config_##__name(struct config_##__name *a) { \ a->ac = 0; \ return CFOK; \ } -#define ARRAY_ATOM(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_STRING(__name, __size, __lbllen, __strsize, __lblparser, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_NODE(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_STRUCT(__name, __size, __lbllen, __structname, __lblparser, __validator...) __ARRAY(__name) +#define KEY_ATOM(__type, __eltparser) +#define KEY_STRING(__strsize, __eltparser) +#define VALUE_ATOM(__type, __eltparser) +#define VALUE_STRING(__strsize, __eltparser) +#define VALUE_NODE(__type, __eltparser) +#define VALUE_SUB_STRUCT(__structname) +#define VALUE_NODE_STRUCT(__structname, __eltparser) +#define END_ARRAY(__size) #include "config_schema.h" #undef STRUCT #undef NODE @@ -283,11 +308,15 @@ strbuf strbuf_cf_flags(strbuf, int); #undef SUB_STRUCT #undef NODE_STRUCT #undef END_STRUCT -#undef __ARRAY -#undef ARRAY_ATOM -#undef ARRAY_STRING -#undef ARRAY_NODE -#undef ARRAY_STRUCT +#undef ARRAY +#undef KEY_ATOM +#undef KEY_STRING +#undef VALUE_ATOM +#undef VALUE_STRING +#undef VALUE_NODE +#undef VALUE_SUB_STRUCT +#undef VALUE_NODE_STRUCT +#undef END_ARRAY /* The Configuration Object Model (COM). The config file is parsed into a tree of these structures * first, then those structures are passed as arguments to the schema parsing functions. @@ -321,22 +350,24 @@ struct cf_om_node { #define NODE_STRUCT(__name, __element, __parser, __flags) \ int __parser(struct config_##__name *, const struct cf_om_node *); #define END_STRUCT -#define __ARRAY(__name, __lblparser, __validator...) \ +#define ARRAY(__name, __validator...) \ int opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ - int __lblparser(char *, size_t, const char *); \ __VALIDATOR(__name, ##__validator) -#define ARRAY_ATOM(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, ##__validator) \ - int __eltparser(__type *, const struct cf_om_node *); -#define ARRAY_STRING(__name, __size, __lbllen, __strsize, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, ##__validator) \ +#define KEY_ATOM(__type, __eltparser) \ + int __eltparser(__type *, const char *); +#define KEY_STRING(__strsize, __eltparser) \ int __eltparser(char *, size_t, const char *); -#define ARRAY_NODE(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, ##__validator) \ +#define VALUE_ATOM(__type, __eltparser) \ + int __eltparser(__type *, const char *); +#define VALUE_STRING(__strsize, __eltparser) \ + int __eltparser(char *, size_t, const char *); +#define VALUE_NODE(__type, __eltparser) \ int __eltparser(__type *, const struct cf_om_node *); -#define ARRAY_STRUCT(__name, __size, __lbllen, __structname, __lblparser, __validator...) \ - __ARRAY(__name, __lblparser, ##__validator) \ +#define VALUE_SUB_STRUCT(__structname) \ int opt_config_##__structname(struct config_##__structname *, const struct cf_om_node *); +#define VALUE_NODE_STRUCT(__structname, __eltparser) \ + int __eltparser(struct config_##__structname *, const struct cf_om_node *); +#define END_ARRAY(__size) #include "config_schema.h" #undef STRUCT #undef NODE @@ -345,10 +376,14 @@ struct cf_om_node { #undef SUB_STRUCT #undef NODE_STRUCT #undef END_STRUCT -#undef __ARRAY -#undef ARRAY_ATOM -#undef ARRAY_STRING -#undef ARRAY_NODE -#undef ARRAY_STRUCT +#undef ARRAY +#undef KEY_ATOM +#undef KEY_STRING +#undef VALUE_ATOM +#undef VALUE_STRING +#undef VALUE_NODE +#undef VALUE_SUB_STRUCT +#undef VALUE_NODE_STRUCT +#undef END_ARRAY #endif //__SERVALDNA_CONFIG_H diff --git a/config_schema.h b/config_schema.h index ee211bae..483294ba 100644 --- a/config_schema.h +++ b/config_schema.h @@ -50,7 +50,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * STRING(80, element2, "boo!", opt_str_nonempty, MANDATORY, "A non-empty string") * END_STRUCT * - * ARRAY_STRUCT(joy, 16, 3, happy, opt_str, opt_str,) + * ARRAY(joy) + * KEY_STRING(3, happy, opt_str) + * VALUE_SUB_STRUCT(happy) + * END_ARRAY(16) * * STRUCT(love) * SUB_STRUCT(happy, thing,) @@ -72,7 +75,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * struct config_joy { * unsigned ac; * struct config_joy__element { - * char label[4]; + * char key[4]; * struct config_happy value; * } av[16]; * }; @@ -88,17 +91,36 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * A schema definition is composed from the following STRUCT and ARRAY definitions: * * STRUCT(name[, validatorfunc]) + * element-declaration + * element-declaration + * ... + * END_STRUCT + * + * where each element-declaration is one of: + * * ATOM(type, element, default, parsefunc, flags, comment) * NODE(type, element, default, parsefunc, flags, comment) * STRING(strlen, element, default, parsefunc, flags, comment) * SUB_STRUCT(structname, element, flags) * NODE_STRUCT(structname, element, parsefunc, flags) - * END_STRUCT * - * ARRAY_ATOM(name, size, labellen, type, labelparsefunc, valueparsefunc[, validatorfunc]) - * ARRAY_STRING(name, size, labellen, strlen, labelparsefunc, valueparsefunc[, validatorfunc]) - * ARRAY_NODE(name, size, type, labellen, labelparsefunc, valueparsefunc[, validatorfunc]) - * ARRAY_STRUCT(name, size, labellen, structname, labelparsefunc[, validatorfunc]) + * ARRAY(name[, validatorfunc]) + * key-declaration + * value-declaration + * END_ARRAY(size) + * + * where key-declaration is one of: + * + * KEY_ATOM(type, parsefunc) + * KEY_STRING(strlen, parsefunc) + * + * and value-declaration is one of: + * + * VALUE_ATOM(type, parsefunc) + * VALUE_STRING(strlen, parsefunc) + * VALUE_NODE(type, parsefunc) + * VALUE_SUB_STRUCT(structname) + * VALUE_NODE_STRUCT(structname, parsefunc) * * The meanings of the parameters are: * @@ -107,20 +129,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * arrays. This label does not appear anywhere in the config file itself; it is purely for * internal code-related purposes. * 'strlen' - * For STRING elements and ARRAY_STRING arrays of strings, gives the maximum length of the - * string. The struct is declared with an array of char[strlen+1] to leave room for a - * terminating nul. - * 'labellen' - * For all ARRAYs, gives the maximum length of the label string. The struct is declared with - * an array of char[labellen+1] to leave room for a terminating nul. + * For STRING, LABEL_STRING and VALUE_STRING, gives the maximum length of the string. The + * string is declared as an array of char[strlen+1] to leave room for a terminating nul. * 'size' * For all ARRAYs, gives the maximum size of the array. * 'type' - * Only used for ATOM, NODE, ARRAY_ATOM and ARRAY_NODE declarations. Gives the C type of the - * element. For STRING and ARRAY_STRING, this is implicitly (const char *). + * Used for ATOM, NODE, LABEL_ATOM, VALUE_ATOM and VALUE_NODE declarations. Gives the C type + * of the element. For STRING, KEY_STRING and VALUE_STRING this is implicitly a char[]. * 'structname' - * Only used for SUB_STRUCT, NODE_STRUCT and ARRAY_STRUCT declarations. Identifies a sub- - * structure by 'name' to nest in the enclosing struct or array. + * Only used for SUB_STRUCT, NODE_STRUCT, VALUE_SUB_STRUCT and VALUE_NODE_STRUCT declarations. + * Identifies a sub- structure by 'name' to nest in the enclosing struct or array. * 'element' * The name of the struct element and the key in the configuration file. This name does appear * in the config file and also in the API, so that an option mamed "some.thing.element1" in the @@ -131,20 +149,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Only used for ATOM and NODE struct elements. Gives the default value for the element if * absent from the config file. * 'parsefunc' - * The function used to parse a VALUE from the config file for a STRUCT element. The and ATOM - * and STRING parse functions take a string argument (const char *) which is the nul-terminated - * text of the VALUE (excluding the trailing \n or \r\n). The NODE and NODE_STRUCT parse - * functions take a pointer to a COM node (const struct cf_om_node *), which is the tree of all - * lines starting with the same partial FULLKEY. - * 'labelparsefunc' - * The function used to parse a KEY from the config file (the ) for each ARRAY element value. - * Takes a string argument (const char *). Returns a CFxxx result code as documented in - * "config.h". - * 'valueparsefunc' - * The function used to parse a VALUE from the config file for each ARRAY element value. The - * ARRAY_ATOM and ARRAY_STRING parse functions take a string argument (const char *). The - * ARRAY_NODE and ARRAY_STRUCT parse functions take a pointer to a COM node (const struct - * cf_om_node *). Returns a CFxxx result code as documented in "config.h". + * The function used to parse a VALUE from the config file for a STRUCT element, or a KEY or + * VALUE for an array element. Parse functions for ATOM, STRING, KEY_ATOM, KEY_STRING, + * VALUE_ATOM and VALUE_STRING all take a string argument (const char *) which is a + * nul-terminated text. The parse functions for NODE, NODE_STRUCT, VALUE_NODE and + * VALUE_NODE_STRUCT take a pointer to a COM node (const struct cf_om_node *), and are + * responsible for parsing the node's text and all of its descendents (children). * 'validatorfunc' * A function that is called after the struct/array is fully parsed and populated. This * function can perform validation checks on the whole struct/array that cannot be performed by @@ -176,11 +186,28 @@ STRING(256, chdir, "/", opt_absolute_path,, "Absolute path END_STRUCT STRUCT(monitor) -STRING(256, socket, DEFAULT_MONITOR_SOCKET_NAME, opt_str_nonempty,, "Name of socket for monitor interface") -ATOM(int, uid, -1, opt_int,, "Allowed UID for monitor socket client") +STRING(256, socket, DEFAULT_MONITOR_SOCKET_NAME, opt_str_nonempty,, "Name of socket for monitor interface") +ATOM(int, uid, -1, opt_int,, "Allowed UID for monitor socket client") END_STRUCT -ARRAY_STRING(argv, 16, 3, 128, opt_argv_label, opt_str, vld_argv) +STRUCT(mdp_iftype) +ATOM(uint32_t, tick_ms, 0, opt_uint32_nonzero,, "Tick interval for this interface type") +END_STRUCT + +ARRAY(mdp_iftypelist) +KEY_ATOM(short, opt_interface_type) +VALUE_SUB_STRUCT(mdp_iftype) +END_ARRAY(5) + +STRUCT(mdp) +ATOM(uint32_t, ticks_per_full_address, 4, opt_uint32_nonzero,, "Ticks to elapse between announcing full SID") +SUB_STRUCT(mdp_iftypelist, iftype,) +END_STRUCT + +ARRAY(argv, vld_argv) +KEY_ATOM(unsigned short, opt_ushort_nonzero) +VALUE_STRING(128, opt_str) +END_ARRAY(16) STRUCT(executable) STRING(256, executable, "", opt_absolute_path, MANDATORY, "Absolute path of dna helper executable") @@ -197,7 +224,10 @@ STRING(256, host, "", opt_str_nonempty, MANDATORY, "Host n ATOM(uint16_t, port, RHIZOME_HTTP_PORT, opt_port,, "Port number") END_STRUCT -ARRAY_NODE(peerlist, 10, 15, struct config_rhizomepeer, opt_str, opt_rhizome_peer) +ARRAY(peerlist) +KEY_STRING(15, opt_str) +VALUE_NODE(struct config_rhizomepeer, opt_rhizome_peer) +END_ARRAY(10) STRUCT(rhizomedirect) SUB_STRUCT(peerlist, peer,) @@ -219,7 +249,10 @@ ATOM(struct in_addr, address, (struct in_addr){0}, opt_in_addr, MANDAT ATOM(uint16_t, port, PORT_DNA, opt_port,, "Port number") END_STRUCT -ARRAY_STRUCT(host_list, 32, SID_STRLEN, host, opt_str_hex_sid) +ARRAY(host_list) +KEY_ATOM(sid_t, opt_sid) +VALUE_SUB_STRUCT(host) +END_ARRAY(32) STRUCT(network_interface) ATOM(int, exclude, 0, opt_boolean,, "If true, do not use matching interfaces") @@ -227,15 +260,20 @@ ATOM(struct pattern_list, match, PATTERN_LIST_EMPTY, opt_pattern_list, MA ATOM(short, type, OVERLAY_INTERFACE_WIFI, opt_interface_type,, "Type of network interface") ATOM(uint16_t, port, RHIZOME_HTTP_PORT, opt_port,, "Port number for network interface") ATOM(uint64_t, speed, 1000000, opt_uint64_scaled,, "Speed in bits per second") +ATOM(uint32_t, mdp_tick_ms, 0, opt_uint32_nonzero,, "Override MDP tick interval for this interface") END_STRUCT -ARRAY_STRUCT(interface_list, 10, 15, network_interface, opt_str) +ARRAY(interface_list) +KEY_STRING(15, opt_str) +VALUE_SUB_STRUCT(network_interface) +END_ARRAY(10) STRUCT(main) NODE_STRUCT(interface_list, interfaces, opt_interface_list, MANDATORY) SUB_STRUCT(log, log,) SUB_STRUCT(server, server,) SUB_STRUCT(monitor, monitor,) +SUB_STRUCT(mdp, mdp,) SUB_STRUCT(dna, dna,) NODE(debugflags_t, debug, 0, opt_debugflags, USES_CHILDREN, "Debug flags") SUB_STRUCT(rhizome, rhizome,) diff --git a/config_test.c b/config_test.c index 8c6ed1c9..c07c0b1e 100644 --- a/config_test.c +++ b/config_test.c @@ -411,11 +411,11 @@ int opt_rhizome_peer(struct config_rhizomepeer *, const struct cf_om_node *node) int opt_str(char *str, size_t len, const char *text); int opt_str_nonempty(char *str, size_t len, const char *text); int opt_int(int *intp, const char *text); +int opt_uint32_nonzero(uint32_t *intp, const char *text); int opt_uint64_scaled(uint64_t *intp, const char *text); int opt_protocol(char *str, size_t len, const char *text); int opt_in_addr(struct in_addr *addrp, const char *text); int opt_port(unsigned short *portp, const char *text); -int opt_str_hex_sid(char *sidhexp, size_t len, const char *text); int opt_sid(sid_t *sidp, const char *text); int opt_interface_type(short *typep, const char *text); int opt_pattern_list(struct pattern_list *listp, const char *text); @@ -431,20 +431,15 @@ int opt_boolean(int *booleanp, const char *text) *booleanp = 0; return CFOK; } - //invalid_text(node, "expecting true|yes|on|1|false|no|off|0"); return CFINVALID; } int opt_absolute_path(char *str, size_t len, const char *text) { - if (text[0] != '/') { - //invalid_text(node, "must start with '/'"); + if (text[0] != '/') return CFINVALID; - } - if (strlen(text) >= len) { - //invalid_text(node, "string overflow"); + if (strlen(text) >= len) return CFSTRINGOVERFLOW; - } strncpy(str, text, len); assert(str[len - 1] == '\0'); return CFOK; @@ -537,14 +532,10 @@ int opt_debugflags(debugflags_t *flagsp, const struct cf_om_node *node) int opt_protocol(char *str, size_t len, const char *text) { - if (!str_is_uri_scheme(text)) { - //invalid_text(node, "contains invalid character"); + if (!str_is_uri_scheme(text)) return CFINVALID; - } - if (strlen(text) >= len) { - //invalid_text(node, "string overflow"); + if (strlen(text) >= len) return CFSTRINGOVERFLOW; - } strncpy(str, text, len); assert(str[len - 1] == '\0'); return CFOK; @@ -564,7 +555,7 @@ int opt_rhizome_peer(struct config_rhizomepeer *rpeer, const struct cf_om_node * && str_uri_hierarchical(node->text, &hier, NULL) && str_uri_hierarchical_authority(hier, &auth, NULL)) ) - goto invalid; + return CFINVALID; } else { auth = node->text; protocol = "http"; @@ -574,23 +565,16 @@ int opt_rhizome_peer(struct config_rhizomepeer *rpeer, const struct cf_om_node * size_t hostlen; unsigned short port = 4110; if (!str_uri_authority_hostname(auth, &host, &hostlen)) - goto invalid; + return CFINVALID; str_uri_authority_port(auth, &port); - if (protolen >= sizeof rpeer->protocol) { - //invalid_text(node, "protocol string overflow"); + if (protolen >= sizeof rpeer->protocol) return CFSTRINGOVERFLOW; - } - if (hostlen >= sizeof rpeer->host) { - //invalid_text(node, "hostname string overflow"); + if (hostlen >= sizeof rpeer->host) return CFSTRINGOVERFLOW; - } strncpy(rpeer->protocol, protocol, protolen)[protolen] = '\0'; strncpy(rpeer->host, host, hostlen)[hostlen] = '\0'; rpeer->port = port; return CFOK; -invalid: - //invalid_text(node, "malformed URL"); - return CFINVALID; } int opt_str(char *str, size_t len, const char *text) @@ -604,10 +588,8 @@ int opt_str(char *str, size_t len, const char *text) int opt_str_nonempty(char *str, size_t len, const char *text) { - if (!text[0]) { - //invalid_text(node, "empty string"); + if (!text[0]) return CFINVALID; - } return opt_str(str, len, text); } @@ -621,56 +603,55 @@ int opt_int(int *intp, const char *text) return CFOK; } +int opt_uint32_nonzero(uint32_t *intp, const char *text) +{ + const char *end = text; + long value = strtoul(text, (char**)&end, 10); + if (end == text || *end || value < 1 || value > 0xffffffffL) + return CFINVALID; + *intp = value; + return CFOK; +} + int opt_uint64_scaled(uint64_t *intp, const char *text) { uint64_t result; const char *end; - if (!str_to_uint64_scaled(text, 10, &result, &end) || *end) { - //invalid_text(node, "invalid scaled unsigned integer"); + if (!str_to_uint64_scaled(text, 10, &result, &end) || *end) return CFINVALID; - } *intp = result; return CFOK; } -int opt_argv_label(char *labelp, size_t len, const char *text) +int opt_ushort_nonzero(unsigned short *ushortp, const char *text) { - const char *s = text; - if (isdigit(*s) && *s != '0') { - ++s; - while (isdigit(*s)) - ++s; - } - if (s == text || *s) + uint32_t ui; + if (opt_uint32_nonzero(&ui, text) != CFOK || ui > 0xffff) return CFINVALID; - if (s - text >= len) - return CFSTRINGOVERFLOW; - strncpy(labelp, text, len - 1)[len - 1] = '\0'; + *ushortp = ui; return CFOK; } int cmp_argv(const struct config_argv__element *a, const struct config_argv__element *b) { - int ai = atoi(a->label); - int bi = atoi(b->label); - return ai < bi ? -1 : ai > bi ? 1 : 0; + return a->key < b->key ? -1 : a->key > b->key ? 1 : 0; } int vld_argv(const struct cf_om_node *parent, struct config_argv *array, int result) { qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) cmp_argv); - int last_label = -1; + unsigned short last_key = 0; int i; for (i = 0; i < array->ac; ++i) { - int label = atoi(array->av[i].label); - assert(label >= 1); - while (last_label != -1 && ++last_label < label && last_label <= sizeof(array->av)) { + unsigned short key = array->av[i].key; + assert(key >= 1); + while (last_key != -1 && ++last_key < key && last_key <= sizeof(array->av)) { char labelkey[12]; - sprintf(labelkey, "%u", last_label); + sprintf(labelkey, "%u", last_key); warn_missing_node(parent, labelkey); result |= CFINCOMPLETE; } - last_label = label; + last_key = key; } return result; } @@ -694,31 +675,17 @@ int opt_port(unsigned short *portp, const char *text) if (port / 10 != oport) break; } - if (*p || port == 0) { - //invalid_text(node, "invalid port number"); + if (*p || port == 0) return CFINVALID; - } *portp = port; return CFOK; } -int opt_str_hex_sid(char *sidhexp, size_t len, const char *text) -{ - if (!str_is_subscriber_id(text)) - return CFINVALID; - if (len <= SID_STRLEN) - return CFSTRINGOVERFLOW; - strncpy(sidhexp, text, SID_STRLEN)[SID_STRLEN] = '\0'; - return CFOK; -} - int opt_sid(sid_t *sidp, const char *text) { sid_t sid; - if (!str_is_subscriber_id(text)) { - //invalid_text(node, "invalid subscriber ID"); + if (!str_is_subscriber_id(text)) return CFINVALID; - } size_t n = fromhex(sidp->binary, text, SID_SIZE); assert(n == SID_SIZE); return CFOK; @@ -742,7 +709,6 @@ int opt_interface_type(short *typep, const char *text) *typep = OVERLAY_INTERFACE_UNKNOWN; return CFOK; } - //invalid_text(node, "invalid network interface type"); return CFINVALID; } @@ -756,10 +722,8 @@ int opt_pattern_list(struct pattern_list *listp, const char *text) if (!*p || isspace(*p) || *p == ',') { if (word) { size_t len = p - word; - if (list.patc >= NELS(list.patv) || len >= sizeof(list.patv[list.patc])) { - //invalid_text(node, "string overflow"); + if (list.patc >= NELS(list.patv) || len >= sizeof(list.patv[list.patc])) return CFARRAYOVERFLOW; - } strncpy(list.patv[list.patc++], word, len)[len] = '\0'; word = NULL; } @@ -912,8 +876,8 @@ int opt_interface_list(struct config_interface_list *listp, const struct cf_om_n switch (ret) { case CFERROR: return CFERROR; case CFOK: - len = snprintf(listp->av[n].label, sizeof listp->av[n].label - 1, "%u", n); - listp->av[n].label[len] = '\0'; + len = snprintf(listp->av[n].key, sizeof listp->av[n].key - 1, "%u", n); + listp->av[n].key[len] = '\0'; ++n; break; default: @@ -1015,22 +979,25 @@ bye: return result; \ } -#define __ARRAY(__name, __lblparser, __parseexpr, __validator...) \ +#define ARRAY(__name, __validator...) \ int opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \ int (*validator)(const struct cf_om_node *, struct config_##__name *, int) = (NULL, ##__validator); \ int result = CFOK; \ int i, n; \ for (n = 0, i = 0; i < node->nodc && n < NELS(array->av); ++i) { \ const struct cf_om_node *child = node->nodv[i]; \ - int ret = __lblparser(array->av[n].label, sizeof array->av[n].label, child->key); \ + int ret = CFEMPTY; +#define __ARRAY_KEY(__parseexpr) \ + ret = (__parseexpr); \ if (ret == CFERROR) \ return CFERROR; \ result |= ret & CF__SUBFLAGS; \ ret &= CF__FLAGS; \ result |= CFSUB(ret); \ if (ret != CFOK) \ - warn_array_label(child, ret); \ - else { \ + warn_array_label(child, ret); +#define __ARRAY_VALUE(__parseexpr) \ + if (ret == CFOK) { \ ret = (__parseexpr); \ if (ret == CFERROR) \ return CFERROR; \ @@ -1041,7 +1008,8 @@ bye: ++n; \ else \ warn_array_value(child, ret); \ - } \ + } +#define END_ARRAY(__size) \ } \ if (i < node->nodc) { \ assert(n == NELS(array->av)); \ @@ -1060,14 +1028,13 @@ bye: result |= CFEMPTY; \ return result; \ } -#define ARRAY_ATOM(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY, ##__validator) -#define ARRAY_STRING(__name, __size, __lbllen, __strsize, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY, ##__validator) -#define ARRAY_NODE(__name, __size, __lbllen, __type, __lblparser, __eltparser, __validator...) \ - __ARRAY(__name, __lblparser, __eltparser(&array->av[n].value, child), ##__validator) -#define ARRAY_STRUCT(__name, __size, __lbllen, __structname, __lblparser, __validator...) \ - __ARRAY(__name, __lblparser, opt_config_##__structname(&array->av[n].value, child), ##__validator) +#define KEY_ATOM(__type, __eltparser) __ARRAY_KEY(__eltparser(&array->av[n].key, child->key)) +#define KEY_STRING(__strsize, __eltparser) __ARRAY_KEY(__eltparser(array->av[n].key, sizeof array->av[n].key, child->key)) +#define VALUE_ATOM(__type, __eltparser) __ARRAY_VALUE(child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY) +#define VALUE_STRING(__strsize, __eltparser) __ARRAY_VALUE(child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY) +#define VALUE_NODE(__type, __eltparser) __ARRAY_VALUE(__eltparser(&array->av[n].value, child)) +#define VALUE_SUB_STRUCT(__structname) __ARRAY_VALUE(opt_config_##__structname(&array->av[n].value, child)) +#define VALUE_NODE_STRUCT(__structname, __eltparser) __ARRAY_VALUE(__eltparser(&array->av[n].value, child)) #include "config_schema.h" @@ -1078,12 +1045,15 @@ bye: #undef SUB_STRUCT #undef NODE_STRUCT #undef END_STRUCT -#undef __ARRAY - -#undef ARRAY_ATOM -#undef ARRAY_STRING -#undef ARRAY_NODE -#undef ARRAY_STRUCT +#undef ARRAY +#undef KEY_ATOM +#undef KEY_STRING +#undef VALUE_ATOM +#undef VALUE_STRING +#undef VALUE_NODE +#undef VALUE_SUB_STRUCT +#undef VALUE_NODE_STRUCT +#undef END_ARRAY int main(int argc, char **argv) { @@ -1122,17 +1092,21 @@ int main(int argc, char **argv) DEBUGF("config.debug = %llx", (unsigned long long) config.debug); DEBUGF("config.directory.service = %s", alloca_tohex(config.directory.service.binary, SID_SIZE)); int j; + for (j = 0; j < config.mdp.iftype.ac; ++j) { + DEBUGF("config.mdp.iftype.%u", config.mdp.iftype.av[j].key); + DEBUGF(" .tick_ms = %u", config.mdp.iftype.av[j].value.tick_ms); + } for (j = 0; j < config.dna.helper.argv.ac; ++j) { - DEBUGF("config.dna.helper.argv.%s=%s", config.dna.helper.argv.av[j].label, config.dna.helper.argv.av[j].value); + DEBUGF("config.dna.helper.argv.%u=%s", config.dna.helper.argv.av[j].key, config.dna.helper.argv.av[j].value); } for (j = 0; j < config.rhizome.direct.peer.ac; ++j) { - DEBUGF("config.rhizome.direct.peer.%s", config.rhizome.direct.peer.av[j].label); + DEBUGF("config.rhizome.direct.peer.%s", config.rhizome.direct.peer.av[j].key); DEBUGF(" .protocol = %s", alloca_str(config.rhizome.direct.peer.av[j].value.protocol)); DEBUGF(" .host = %s", alloca_str(config.rhizome.direct.peer.av[j].value.host)); DEBUGF(" .port = %u", config.rhizome.direct.peer.av[j].value.port); } for (j = 0; j < config.interfaces.ac; ++j) { - DEBUGF("config.interfaces.%s", config.interfaces.av[j].label); + DEBUGF("config.interfaces.%s", config.interfaces.av[j].key); DEBUGF(" .exclude = %d", config.interfaces.av[j].value.exclude); DEBUGF(" .match = ["); int k; @@ -1144,7 +1118,9 @@ int main(int argc, char **argv) DEBUGF(" .speed = %llu", (unsigned long long) config.interfaces.av[j].value.speed); } for (j = 0; j < config.hosts.ac; ++j) { - DEBUGF("config.hosts.%s", config.hosts.av[j].label); + char sidhex[SID_STRLEN + 1]; + tohex(sidhex, config.hosts.av[j].key.binary, SID_SIZE); + DEBUGF("config.hosts.%s", sidhex); DEBUGF(" .interface = %s", alloca_str(config.hosts.av[j].value.interface)); DEBUGF(" .address = %s", inet_ntoa(config.hosts.av[j].value.address)); DEBUGF(" .port = %u", config.hosts.av[j].value.port);