/* Serval DNA configuration Copyright (C) 2012 Serval Project Inc. 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This file contains definitions for the schema of the Serval DNA configuration file. See comments * in "config.h" for a description of the internal configuration API. * * A configuration schema is set of nested structures and arrays. By convention, the top level, or * root of the schema is called "main", but every structure and array has its own complete API which * can be used by itself. So if there were two independent configuration files, both could be * defined in this file, each with a conventional name for its own root element. * * A configuration file consists of lines of the form: * * FULLKEY "=" VALUE "\n" * * where FULLKEY has the form KEY [ "." KEY [ "." KEY [ ... ] ] ] and VALUE is any string not * containing newline. Lines ending with "\r\n" have the "\r" stripped from the end of VALUE. * Otherwise VALUE is preserved exactly, with all leading and trailing spaces intact. * * To describe a configuration file that looks like this: * * some.thing.element1=integer * some.thing.element2=string * some.list.foo.element1=integer * some.list.foo.element2=string * some.list.bar.element1=integer * some.list.bar.element2=string * another_thing=http://my.host.com:1234/path/to/nowhere * * the following schema would do: * * STRUCT(happy) * ATOM(int32_t, element1, 0, int32_nonneg,, "An integer >= 0") * STRING(80, element2, "boo!", str_nonempty, MANDATORY, "A non-empty string") * END_STRUCT * * ARRAY(joy,) * KEY_STRING(3, happy, str) * VALUE_SUB_STRUCT(happy) * END_ARRAY(16) * * STRUCT(love) * SUB_STRUCT(happy, thing,) * SUB_STRUCT(joy, list,) * END_STRUCT * * STRUCT(main) * SUB_STRUCT(love, some,) * STRING(128, another_thing, "", uri,, "URL; protocol://hostname[:port][/path]") * END_STRUCT * * which would produce an API based on the following definitions (see "config.h" for more * information): * * struct config_happy { * int32_t element1; * char element2[81]; * }; * struct config_joy { * unsigned ac; * struct config_joy__element { * char key[4]; * struct config_happy value; * } av[16]; * }; * struct config_love { * struct config_happy thing; * struct config_joy list; * }; * struct config_main { * struct config_love some; * char another_thing[129]; * }; * * A schema definition is composed from the following STRUCT and ARRAY definitions: * * STRUCT(name) [ VALIDATOR(validatorfunc) ] * element-declaration * element-declaration * ... * END_STRUCT * * where each element-declaration is one of: * * ATOM(type, element, default, repr, flags, comment) * NODE(type, element, default, repr, flags, comment) * STRING(strlen, element, default, repr, flags, comment) * SUB_STRUCT(structname, element, flags [, default_label]) * NODE_STRUCT(structname, element, repr, flags [, default_label]) * * ARRAY(name, flags) [ VALIDATOR(validatorfunc) ] * key-declaration * value-declaration * END_ARRAY(size) * * where key-declaration is one of: * * KEY_ATOM(type, repr) * KEY_STRING(strlen, repr) * * and value-declaration is one of: * * VALUE_ATOM(type, repr) * VALUE_STRING(strlen, repr) * VALUE_NODE(type, repr) * VALUE_SUB_STRUCT(structname) * VALUE_NODE_STRUCT(structname, repr) * * For defining alternative STRUCT default settings: * * STRUCT_DEFAULT(name, default_label) * default-declaration * default-declaration * ... * END_STRUCT_DEFAULT * * where each default-declaration is one of: * * ATOM_DEFAULT(element, default) * STRING_DEFAULT(element, default) * SUB_STRUCT_DEFAULT(structname, element [, default_label]) * * Every structure defined by STRUCT has its own, native default values as given by * the 'default' parameter in each of its element declarations. The STRUCT_DEFAULT * declaration defines a variation on the default values that can be used to give the * structure alternative defaults when included as a SUB_STRUCT (or NODE_STRUCT) from * within another structure. Not all the STRUCT's elements have to be defined within * a STRUCT_DEFAULT definition; any omitted ones take the STRUCT's native default. * * For defining that one STRUCT can be treated as a subset of another: * * STRUCT_ASSIGN(substruct, superstruct) * element-declaration * element-declaration * ... * END_STRUCT_ASSIGN * * where element-declaration is exactly as for STRUCT(...) above. * * This generates a structure copy function that copies the given elements of 'substruct' * into the equivalent elements of 'superstruct'; ie, both structures must have the same * element names and types. * * The meanings of the parameters are: * * 'name' * A label used to qualify this struct/array's API from the API components of other structs and * arrays. This label does not appear anywhere in the config file itself; it is purely for * internal code-related purposes. * 'strlen' * 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' * 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 char[strlen+1]. * 'structname' * 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 * file is referred to as some.thing.element1 in the C code. Arrays are more complicated: * "some.list.foo.element1" in the config file is referred to as some.list.av[n].value.element1 * in the C code, and some.list.ac gives the size of the some.list.av array. * 'default' * Only used for ATOM and NODE struct elements. Gives the default value for the element if * absent from the config file. * 'repr' * The string representation. This name specifies a trio of functions, cf_opt_(), * cf_fmt_() and cf_cmp_(): * - The cf_opt_() functions for ATOM, STRING, KEY_ATOM, KEY_STRING, VALUE_ATOM and * VALUE_STRING take a (const char *) argument pointing to nul-terminated text. The * functions for NODE and VALUE_NODE 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). * - Each cf_fmt_() function is the inverse of cf_opt_. The cf_fmt_ * functions for ATOM, KEY_ATOM, KEY_STRING, VALUE_ATOM and VALUE_STRING all take a pointer * to a const 'type', and produce a malloc()ed nul-terminated string which, if passed to * cf_opt_(), would produce the same original value. If the value is invalid (outside * the legal range) then cf_fmt_ returns CFINVALID or CFEMPTY. The cf_fmt_ * functions for NODE and VALUE_NODE take a pointer to a const 'type' and produce a * malloc()ed COM node (struct cf_om_node *) which, if passed to cf_opt_ would produce * the same original value. * - Each cf_cmp_() function compares two values of the given 'type' and returns -1, 0 * or 1 to indicate the natural ordering of the values. These functions are used to detect * when config elements have their default values, to avoid calling cf_fmt_(). They * are also used to sort array keys. * '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 * the parse functions of each element in isolation, and can even alter the contents of the * struct/array, eg, sort an array or fill in default values in structs that depend on other * elements. Takes as its second argument the CFxxx code produced by the parser, and returns * an updated CFxxx result code (which could be the same) as documented in "config.h". * 'flags' * A space-separated list of flags. At present only the MANDATORY flag is supported, which * will cause parsing to fail if the given STRUCT element is not set in the config file. In * the case of struct elements that are arrays, the config file must set at least one element * of the array, or parsing fails. * 'comment' * A human-readable string describing the value of the configuration option. Must be * informative enough to help users diagnose parse errors. Eg, "An integer" is not enough; * better would be "Integer >= 0, number of seconds since Unix epoch". * 'default_label' * A label used to qualify an alternative STRUCT default set. These labels need only be unique * for each given struct 'name', so different STRUCTs may re-use the same labels. * * @author Andrew Bettison */ STRUCT(debug) ATOM(bool_t, verbose, 0, boolean,, "") ATOM(bool_t, ack, 0, boolean,, "") ATOM(bool_t, config, 0, boolean,, "") ATOM(bool_t, dnahelper, 0, boolean,, "") ATOM(bool_t, timing, 0, boolean,, "") ATOM(bool_t, http_server, 0, boolean,, "") ATOM(bool_t, httpd, 0, boolean,, "") ATOM(bool_t, nohttptx, 0, boolean,, "") ATOM(bool_t, io, 0, boolean,, "") ATOM(bool_t, verbose_io, 0, boolean,, "") ATOM(bool_t, keyring, 0, boolean,, "") ATOM(bool_t, mdprequests, 0, boolean,, "") ATOM(bool_t, mdp_filter, 0, boolean,, "") ATOM(bool_t, msp, 0, boolean,, "") ATOM(bool_t, monitor, 0, boolean,, "") ATOM(bool_t, radio_link, 0, boolean,, "") ATOM(bool_t, overlaybuffer, 0, boolean,, "") ATOM(bool_t, overlayframes, 0, boolean,, "") ATOM(bool_t, packets_sent, 0, boolean,, "") ATOM(bool_t, overlayrouting, 0, boolean,, "") ATOM(bool_t, overlayinterfaces, 0, boolean,, "") ATOM(bool_t, broadcasts, 0, boolean,, "") ATOM(bool_t, packettx, 0, boolean,, "") ATOM(bool_t, packetrx, 0, boolean,, "") ATOM(bool_t, packetradio, 0, boolean,, "") ATOM(bool_t, rhizome, 0, boolean,, "") ATOM(bool_t, rhizome_manifest, 0, boolean,, "") ATOM(bool_t, rhizome_sql_bind, 0, boolean,, "") ATOM(bool_t, rhizome_store, 0, boolean,, "") ATOM(bool_t, rhizome_sync, 0, boolean,, "") ATOM(bool_t, rhizome_sync_keys, 0, boolean,, "") ATOM(bool_t, rhizome_tx, 0, boolean,, "") ATOM(bool_t, rhizome_rx, 0, boolean,, "") ATOM(bool_t, rhizome_ads, 0, boolean,, "") ATOM(bool_t, rhizome_mdp_rx, 0, boolean,, "") ATOM(bool_t, rhizome_direct, 0, boolean,, "") ATOM(bool_t, subscriber, 0, boolean,, "") ATOM(bool_t, meshms, 0, boolean,, "") ATOM(bool_t, vomp, 0, boolean,, "") ATOM(bool_t, profiling, 0, boolean,, "") ATOM(bool_t, linkstate, 0, boolean,, "") ATOM(bool_t, watchdog, 0, boolean,, "") END_STRUCT #define LOG_FORMAT_OPTIONS \ ATOM(bool_t, show_pid, 1, boolean,, "If true, all log lines contain PID of logging process") \ ATOM(bool_t, show_time, 1, boolean,, "If true, all log lines contain time stamp") \ ATOM(int, level, LOG_LEVEL_DEBUG, log_level,, "Only log messages at and above this level of severity") \ ATOM(bool_t, dump_config, 1, boolean,, "If true, current configuration is dumped into start of log") STRUCT(log_format) LOG_FORMAT_OPTIONS END_STRUCT STRUCT(log_format_file) STRING(256, directory_path, "", str,, "Path of directory for log files, either absolute or relative to instance log directory") STRING(256, path, "", str_nonempty,, "Path of single log file, either absolute or relative to directory_path") ATOM(unsigned short, rotate, 12, ushort,, "Number of log files to rotate, zero means no deletion") ATOM(uint32_t, duration, 3600, uint32_time_interval,, "Time duration of each log file, zero means one file per invocation") LOG_FORMAT_OPTIONS END_STRUCT STRUCT_ASSIGN(log_format, log_format_file) LOG_FORMAT_OPTIONS END_STRUCT_ASSIGN STRUCT(log) SUB_STRUCT(log_format_file, file,,) SUB_STRUCT(log_format, console,, console) SUB_STRUCT(log_format, android,, android) END_STRUCT STRUCT_DEFAULT(log_format, console) ATOM_DEFAULT(show_pid, 0) ATOM_DEFAULT(show_time, 0) ATOM_DEFAULT(level, LOG_LEVEL_HINT) ATOM_DEFAULT(dump_config, 0) END_STRUCT_DEFAULT STRUCT_DEFAULT(log_format, android) ATOM_DEFAULT(show_pid, 0) ATOM_DEFAULT(show_time, 0) END_STRUCT_DEFAULT STRUCT(watchdog) STRING(256, executable, "", absolute_path,, "Absolute path of watchdog executable") ATOM(uint32_t, interval_ms, 60000, uint32_nonzero,, "Time interval between watchdog invocations, in milliseconds") END_STRUCT STRUCT(server) STRING(256, chdir, "/", absolute_path,, "Absolute path of chdir(2) for server process") STRING(256, interface_path, "", str_nonempty,, "Path of directory containing interface files, either absolute or relative to instance directory") ATOM(uint32_t, config_reload_interval_ms, 1000, uint32_nonzero,, "Time interval between configuration reload polls, in milliseconds") SUB_STRUCT(watchdog, watchdog,) STRING(120, motd, "", str_nonempty,, "Message Of The Day displayed on HTTPD root page") END_STRUCT STRUCT(monitor) ATOM(uint32_t, uid, 0, uint32_nonzero,, "Allowed UID for monitor socket client") END_STRUCT STRUCT(mdp_iftype) ATOM(int32_t, mtu, 1200, int32_nonneg,, "Maximum transmision size") ATOM(int32_t, tick_ms, -1, int32_nonneg,, "Keep alive interval") ATOM(int32_t, packet_interval, -1, int32_nonneg,, "Minimum interval between packets in microseconds") ATOM(int32_t, reachable_timeout_ms, -1, int32_nonneg,, "Inactivity timeout after which node considered unreachable") ATOM(int32_t, transmit_timeout_ms, 1000, int32_nonneg,, "Maximum duration to hold a packet before transmission") ATOM(bool_t, drop, 0, boolean,, "If true, drop all incoming packets") ATOM(bool_t, send, 1, boolean,, "If false, don't send any packets") ATOM(bool_t, route, 1, boolean,, "If false, do not advertise any links") ATOM(short, encapsulation, ENCAP_OVERLAY, encapsulation,, "Type of packet encapsulation") END_STRUCT STRUCT(mdp) ATOM(bool_t, enable_inet, 0, boolean,, "If true, allow mdp clients to connect over loopback UDP") STRING(256, filter_rules_path, "", str_nonempty,, "Path of file containing MDP filter rules, either absolute or relative to instance directory") END_STRUCT STRUCT(vomp) ATOM(int32_t, dial_timeout_ms, 15000, int32_nonneg,, "Timeout to establish a call when dialling") ATOM(int32_t, ring_timeout_ms, 30000, int32_nonneg,, "Timeout for the other user to answer") ATOM(int32_t, network_timeout_ms, 30000, int32_nonneg,, "Timeout for network activity until a call will end") END_STRUCT STRUCT(olsr) ATOM(bool_t, enable, 0, boolean,, "If true, OLSR is used for mesh routing") ATOM(uint16_t, remote_port, 4130, uint16_nonzero,, "Remote port number") ATOM(uint16_t, local_port, 4131, uint16_nonzero,, "Local port number") END_STRUCT ARRAY(argv, NO_DUPLICATES, VALIDATOR(vld_argv)) KEY_ATOM(unsigned short, ushort_nonzero) VALUE_STRING(128, str) END_ARRAY(16) STRUCT(executable) STRING(256, executable, "", absolute_path, MANDATORY, "Absolute path of dna helper executable") SUB_STRUCT(argv, argv,) END_STRUCT STRUCT(dna) SUB_STRUCT(executable, helper,) END_STRUCT STRUCT(rhizome_peer) STRING(25, protocol, "http", protocol,, "Protocol name") STRING(256, host, "", str_nonempty, MANDATORY, "Host name or IP address") ATOM(uint16_t, port, HTTPD_PORT_DEFAULT, uint16_nonzero,, "Port number") END_STRUCT ARRAY(peerlist,) KEY_STRING(15, str) VALUE_NODE_STRUCT(rhizome_peer, rhizome_peer) END_ARRAY(10) STRUCT(rhizome_direct) SUB_STRUCT(peerlist, peer,) END_STRUCT STRUCT(rhizome_api_addfile) STRING(64, uri_path, "", absolute_path,, "URI path for HTTP add-file request") ATOM(struct in_addr, allow_host, hton_in_addr(INADDR_LOOPBACK), in_addr,, "IP address of host allowed to make HTTP add-file request") STRING(256, manifest_template_file, "", str_nonempty,, "Path of manifest template file, either absolute or relative to instance directory") ATOM(sid_t, default_author, SID_ANY, sid,, "Author of add-file bundle if sender not given") ATOM(rhizome_bk_t, bundle_secret_key, RHIZOME_BK_NONE, rhizome_bk,, "Secret key of add-file bundle to try if sender not given") END_STRUCT STRUCT(rhizome_api) SUB_STRUCT(rhizome_api_addfile, addfile,) END_STRUCT STRUCT(rhizome_http) ATOM(bool_t, enable, 1, boolean,, "If true, Rhizome HTTP server is started") ATOM(uint16_t, port, HTTPD_PORT_DEFAULT, uint16_nonzero,, "Port number for Rhizome HTTP server") END_STRUCT STRUCT(rhizome_mdp) ATOM(bool_t, enable, 1, boolean,, "If true, Rhizome MDP server is started") END_STRUCT STRUCT(rhizome_advertise) ATOM(bool_t, enable, 1, boolean,, "If true, Rhizome advertisements are sent") ATOM(uint32_t, interval, 500, uint32_nonzero,, "Interval between Rhizome advertisements") END_STRUCT STRUCT(rhizome) ATOM(bool_t, enable, 1, boolean,, "If true, server opens Rhizome database when starting") ATOM(bool_t, fetch, 1, boolean,, "If false, no new bundles will be fetched from peers") ATOM(bool_t, clean_on_open, 0, boolean,, "If true, Rhizome database is cleaned at start of every command") STRING(256, datastore_path, "", str_nonempty,, "Path of rhizome storage directory, absolute or relative to instance directory") ATOM(uint64_t, database_size, UINT64_MAX, uint64_scaled,, "Maximum size of database in bytes") ATOM(uint64_t, min_free_space, 100*1024*1024, uint64_scaled,, "Minimum free space to preserve on the disk") ATOM(uint32_t, max_blob_size, 128 * 1024, uint32_scaled,, "Store payloads larger than this in files not SQLite blobs") ATOM(uint64_t, rhizome_mdp_block_size, 512, uint64_scaled,, "Rhizome MDP block size.") ATOM(uint64_t, idle_timeout, RHIZOME_IDLE_TIMEOUT, uint64_scaled,, "Rhizome transfer timeout if no data received.") ATOM(uint64_t, mdp_stall_timeout, 1000, uint64_scaled,, "Timeout to request more data via mdp.") ATOM(uint32_t, fetch_delay_ms, 50, uint32_nonzero,, "Delay from receiving first bundle advert to initiating fetch") SUB_STRUCT(rhizome_direct, direct,) SUB_STRUCT(rhizome_api, api,) SUB_STRUCT(rhizome_http, http,) SUB_STRUCT(rhizome_mdp, mdp,) SUB_STRUCT(rhizome_advertise, advertise,) END_STRUCT STRUCT(directory) ATOM(sid_t, service, SID_ANY, sid,, "Subscriber ID of Serval Directory Service") END_STRUCT STRUCT(host) STRING(INTERFACE_NAME_STRLEN, interface, "", str_nonempty,, "Interface name") STRING(256, host, "", str_nonempty,, "Host Name") ATOM(struct in_addr, address, hton_in_addr(INADDR_NONE), in_addr,, "Host IP address") ATOM(uint16_t, port, PORT_DNA, uint16_nonzero,, "Port number") END_STRUCT ARRAY(host_list, NO_DUPLICATES) KEY_ATOM(sid_t, sid) VALUE_SUB_STRUCT(host) END_ARRAY(32) STRUCT(network_interface, VALIDATOR(vld_network_interface)) ATOM(bool_t, exclude, 0, boolean,, "If true, do not use matching interfaces") ATOM(struct pattern_list, match, PATTERN_LIST_EMPTY, pattern_list,, "Names that match network interface") ATOM(short, socket_type, SOCK_UNSPECIFIED, socket_type,, "Type of network socket; stream, dgram or file") STRING(256, file, "", str_nonempty,, "Path of interface file, absolute or relative to server.interface_path") ATOM(struct in_addr, dummy_address, hton_in_addr(INADDR_LOOPBACK), in_addr,, "Dummy interface address") ATOM(struct in_addr, dummy_netmask, hton_in_addr(0xFFFFFF00), in_addr,, "Dummy interface netmask") ATOM(uint16_t, port, PORT_DNA, uint16_nonzero,, "Port number for network interface") ATOM(uint16_t, drop_packets, 0, uint16_nonzero,, "Percentage of incoming packets that should be dropped for testing purposes") ATOM(short, type, OVERLAY_INTERFACE_WIFI, interface_type,, "Type of network interface") ATOM(short, radiotype, RADIO_TYPE_RFD900, radio_type,, "Type of packet radio interface") SUB_STRUCT(mdp_iftype, broadcast,) SUB_STRUCT(mdp_iftype, unicast,) ATOM(bool_t, default_route, 0, boolean,, "If true, use this interface as a default route") ATOM(bool_t, prefer_unicast, 1, boolean,, "If true, send data as unicast IP packets if available") ATOM(bool_t, debug, 0, boolean,, "If true, log details of every outgoing packet") ATOM(bool_t, point_to_point, 0, boolean,, "If true, assume there will only be two devices on this interface") ATOM(bool_t, ctsrts, 0, boolean,, "If true, enable CTS/RTS hardware handshaking") ATOM(int32_t, uartbps, 57600, int32_rs232baudrate,, "Speed of serial UART link speed (which may be different to serial device link speed)") END_STRUCT ARRAY(interface_list, NO_DUPLICATES) KEY_ATOM(unsigned, uint) VALUE_NODE_STRUCT(network_interface, network_interface) END_ARRAY(10) STRUCT(user) STRING(50, password, "", str,, "Authentication password") END_STRUCT ARRAY(userlist,) KEY_STRING(25, str) VALUE_SUB_STRUCT(user) END_ARRAY(10) STRUCT(api_restful) SUB_STRUCT(userlist, users,) ATOM(uint32_t, newsince_timeout, 60, uint32_time_interval,, "Time to block while reporting new bundles") END_STRUCT STRUCT(api) SUB_STRUCT(api_restful, restful,) END_STRUCT // The top level. STRUCT(main) NODE_STRUCT(interface_list, interfaces, interface_list,) SUB_STRUCT(log, log,) SUB_STRUCT(server, server,) SUB_STRUCT(monitor, monitor,) SUB_STRUCT(mdp, mdp,) SUB_STRUCT(dna, dna,) SUB_STRUCT(vomp, vomp,) SUB_STRUCT(debug, debug,) SUB_STRUCT(rhizome, rhizome,) SUB_STRUCT(directory, directory,) SUB_STRUCT(olsr, olsr,) SUB_STRUCT(host_list, hosts,) SUB_STRUCT(api, api,) END_STRUCT