diff --git a/Makefile.in b/Makefile.in index 75d47a30..96e25911 100755 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,9 @@ endif SRCS= $(NACL_SOURCES) $(SERVAL_SOURCES) MONITORCLIENTSRCS=conf.c \ + conf_om.c \ + conf_parse.c \ + conf_schema.c \ log.c \ os.c \ mem.c \ @@ -28,6 +31,9 @@ MONITORCLIENTSRCS=conf.c \ strbuf_helpers.c MDPCLIENTSRCS=conf.c \ + conf_om.c \ + conf_parse.c \ + conf_schema.c \ dataformats.c \ os.c \ mem.c \ diff --git a/commandline.c b/commandline.c index e8a40aba..63fe5ad8 100644 --- a/commandline.c +++ b/commandline.c @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #endif #include "serval.h" +#include "conf.h" #include "rhizome.h" #include "strbuf.h" #include "str.h" @@ -188,7 +189,7 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args) { fd_clearstats(); IN(); - confSetDebugFlags(); + cf_reload(); int result = cli_execute(argv0, argc, args, command_line_options, NULL); /* clean up after ourselves */ @@ -376,14 +377,10 @@ void lookup_send_request(unsigned char *srcsid, int srcport, unsigned char *dsts /* Also send an encrypted unicast request to a configured directory service */ if (!dstsid){ - const char *directory_service = confValueGet("directory.service", NULL); - if (directory_service){ - if (stowSid(mdp.out.dst.sid, 0, directory_service)==-1){ - WHYF("Invalid directory server SID %s", directory_service); - }else{ - mdp.packetTypeAndFlags=MDP_TX; - overlay_mdp_send(&mdp,0,0); - } + if (!is_sid_any(config.directory.service.binary)) { + memcpy(mdp.out.dst.sid, config.directory.service.binary, SID_SIZE); + mdp.packetTypeAndFlags=MDP_TX; + overlay_mdp_send(&mdp,0,0); } } } @@ -570,10 +567,8 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti return -1; /* Now that we know our instance path, we can ask for the default set of network interfaces that we will take interest in. */ - const char *interfaces = confValueGet("interfaces", ""); - if (!interfaces[0]) - WHY("No network interfaces configured (empty 'interfaces' config setting)"); - overlay_interface_args(interfaces); + if (config.interfaces.ac == 0) + WARN("No network interfaces configured (empty 'interfaces' config option)"); if (pid == -1) pid = server_pid(); if (pid < 0) @@ -598,7 +593,7 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti return server(NULL); const char *dir = getenv("SERVALD_SERVER_CHDIR"); if (!dir) - dir = confValueGet("server.chdir", "/"); + dir = config.server.chdir; switch (cpid = fork()) { case -1: /* Main process. Fork failed. There is no child process. */ @@ -940,9 +935,9 @@ int app_config_set(int argc, const char *const *argv, struct command_line_option // Bingo, the old version of servald.conf is what remains. This kludge intervenes in step 4, by // reading the new servald.conf into the memory buffer before applying the "rhizome.enable" set // value and overwriting. - confReloadIfChanged(); + struct cf_om_node *root = cf_om_reload(); // - return confValueSet(var, val) == -1 ? -1 : confWrite(); + return root == NULL ? -1 : cf_om_set(&root, var, val) == -1 ? -1 : cf_om_save(root); } int app_config_del(int argc, const char *const *argv, struct command_line_option *o, void *context) @@ -954,9 +949,9 @@ int app_config_del(int argc, const char *const *argv, struct command_line_option if (create_serval_instance_dir() == -1) return -1; // See app_config_set() - confReloadIfChanged(); + struct cf_om_node *root = cf_om_reload(); // - return confValueSet(var, NULL) == -1 ? -1 : confWrite(); + return root == NULL ? -1 : cf_om_set(&root, var, NULL) == -1 ? -1 : cf_om_save(root); } int app_config_get(int argc, const char *const *argv, struct command_line_option *o, void *context) @@ -967,8 +962,9 @@ int app_config_get(int argc, const char *const *argv, struct command_line_option return -1; if (create_serval_instance_dir() == -1) return -1; + struct cf_om_node *root = cf_om_reload(); if (var) { - const char *value = confValueGet(var, NULL); + const char *value = cf_om_get(root, var); if (value) { cli_puts(var); cli_delim("="); @@ -976,15 +972,14 @@ int app_config_get(int argc, const char *const *argv, struct command_line_option cli_delim("\n"); } } else { - int n = confVarCount(); - if (n == -1) - return -1; - unsigned int i; - for (i = 0; i != n; ++i) { - cli_puts(confVar(i)); - cli_delim("="); - cli_puts(confValue(i)); - cli_delim("\n"); + struct cf_om_iterator it; + for (cf_om_iter_start(&it, root); it.node; cf_om_iter_next(&it)) { + if (it.node->text) { + cli_puts(it.node->fullkey); + cli_delim("="); + cli_puts(it.node->text); + cli_delim("\n"); + } } } return 0; diff --git a/conf.c b/conf.c index 285b6ccf..d73f575f 100644 --- a/conf.c +++ b/conf.c @@ -1,6 +1,6 @@ /* -Serval Distributed Numbering Architecture (DNA) -Copyright (C) 2010-2012 Paul Gardner-Stephen +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 @@ -23,208 +23,108 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "log.h" #include "str.h" - -/* This predicate function defines the constraints on configuration option names. - Valid: - foo - foo.bar - foo.bar.chow - _word - word1 - word_1 - Invalid: - foo. - .foo - 1foo - foo.bar. - 12 - 1.2.3 - foo bar - @author Andrew Bettison - */ -int is_configvarname(const char *arg) -{ - if (arg[0] == '\0') - return 0; - if (!(isalnum(arg[0]) || arg[0] == '_')) - return 0; - const char *s = arg + 1; - for (; *s; ++s) - if (!(isalnum(*s) || *s == '_' || (*s == '.' && s[-1] != '.'))) - return 0; - return s[-1] != '.'; -} +#include "mem.h" #define CONFFILE_NAME "serval.conf" -#define MAX_CONFIG_VARS (100) -#define CONFIG_BUFFER_ALLOCSIZE (1024) -static int busy = 0; -static time_t config_timestamp = 0; -static char *config_buffer = NULL; -static char *config_buffer_top = NULL; -static char *config_buffer_end = NULL; -static unsigned int confc = 0; -static char *confvar[MAX_CONFIG_VARS]; -static char *confvalue[MAX_CONFIG_VARS]; +struct file_meta { + time_t mtime; + off_t size; +}; -#define BUSY_BODY(_type, _return_if_busy, _return) \ - do { if (busy) { return (_return_if_busy); } else { busy = 1; _type ret = (_return); busy = 0; return ret; } } while (0) +static struct file_meta conffile_meta = { .mtime = -1, .size = -1 }; +static struct cf_om_node *cf_om_root = NULL; -static char *grow_config_buffer(size_t needed) +int cf_limbo = 1; +struct config_main config; +static struct file_meta config_meta = { .mtime = -1, .size = -1 }; + +static const char *conffile_path() { - size_t cursize = config_buffer_end - config_buffer; - size_t used = config_buffer_top - config_buffer; - size_t newsize = used + needed; - if (newsize > cursize) { - // Round up to nearest multiple of CONFIG_BUFFER_ALLOCSIZE. - newsize = newsize + CONFIG_BUFFER_ALLOCSIZE - ((newsize - 1) % CONFIG_BUFFER_ALLOCSIZE + 1); - char *newbuf = realloc(config_buffer, newsize); - if (newbuf == NULL) { - WHYF_perror("realloc(%llu)", newsize); - return NULL; - } - ssize_t dif = newbuf - config_buffer; - unsigned int i; - for (i = 0; i != confc; ++i) { - confvar[i] += dif; - confvalue[i] += dif; - } - config_buffer_end = newbuf + newsize; - config_buffer_top = newbuf + used; - config_buffer = newbuf; - } - char *ret = config_buffer_top; - config_buffer_top += needed; - return ret; + static char path[1024] = ""; + if (!path[0] && !FORM_SERVAL_INSTANCE_PATH(path, CONFFILE_NAME)) + abort(); + return path; } -static int _read_config() +static int get_meta(const char *path, struct file_meta *metap) { - char conffile[1024]; - if (!FORM_SERVAL_INSTANCE_PATH(conffile, CONFFILE_NAME)) - return -1; - size_t size = 0; - confc = 0; - int exists = 0; - FILE *f = fopen(conffile, "r"); - if (f == NULL) { + struct stat st; + if (stat(path, &st) == -1) { if (errno != ENOENT) - return WHYF_perror("fopen(%s)", conffile); - INFOF("non-existent config file %s", conffile); - config_timestamp = 0; + return WHYF_perror("stat(%s)", path); + metap->size = 0; + metap->mtime = -1; } else { - exists = 1; - struct stat st; - if (fstat(fileno(f), &st) == -1) { - WHYF_perror("fstat(%s)", conffile); - fclose(f); - return -1; + metap->size = st.st_size; + metap->mtime = st.st_mtime; + } + return 0; +} + +static int load() +{ + const char *path = conffile_path(); + struct file_meta meta; + if (get_meta(path, &meta) == -1) + return CFERROR; + char *buf = NULL; + if (meta.mtime == -1) + INFOF("config file %s does not exist", path); + else if (meta.size > CONFIG_FILE_MAX_SIZE) { + WHYF("config file %s is too big (%ld bytes exceeds limit %ld)", path, meta.size, CONFIG_FILE_MAX_SIZE); + return CFERROR; + } else { + FILE *f = fopen(path, "r"); + if (f == NULL) { + WHYF_perror("fopen(%s)", path); + return CFERROR; } - if (fseeko(f, (off_t) 0, SEEK_END) == -1) { - WHYF_perror("fseeko(%s, 0, SEEK_END)", conffile); + if ((buf = emalloc(meta.size)) == NULL) { fclose(f); - return -1; + return CFERROR; } - off_t tell = ftello(f); - if (tell == -1) { - WHYF_perror("ftello(%s)", conffile); - fclose(f); - return -1; - } - size = tell; - if (fseeko(f, (off_t) 0, SEEK_SET) == -1) { - WHYF_perror("fseeko(%s, 0, SEEK_SET)", conffile); - fclose(f); - return -1; - } - if (grow_config_buffer(size) == NULL) { - fclose(f); - return -1; - } - config_timestamp = 0; - if (fread(config_buffer, size, 1, f) != 1) { + if (fread(buf, meta.size, 1, f) != 1) { if (ferror(f)) - WHYF_perror("fread(%s, %llu)", conffile, (unsigned long long) size); + WHYF_perror("fread(%s, %llu)", path, (unsigned long long) meta.size); else - WHYF("fread(%s, %llu) hit EOF", conffile, (unsigned long long) size); - free(config_buffer); - config_buffer = NULL; + WHYF("fread(%s, %llu) hit EOF", path, (unsigned long long) meta.size); + free(buf); fclose(f); + return CFERROR; + } + if (fclose(f) == EOF) { + free(buf); + return WHYF_perror("fclose(%s)", path); + } + INFOF("config file %s successfully read", path); + } + struct cf_om_node *new_root = NULL; + int result = cf_om_parse(path, buf, meta.size, &new_root); + free(buf); + if (result != CFERROR) { + cf_om_free_node(&cf_om_root); + cf_om_root = new_root; + conffile_meta = meta; + } + return result; +} + +static int has_changed(const struct file_meta *metap) +{ + const char *path = conffile_path(); + struct file_meta meta; + if (get_meta(path, &meta) == -1) return -1; - } - config_timestamp = st.st_mtime; - if (fclose(f) == EOF) - return WHYF_perror("fclose(%s)", conffile); - INFOF("successfully read %s", conffile); - } - config_buffer_top = config_buffer + size; - char *c = config_buffer; - char *e = config_buffer_top; - unsigned int linenum; - char *problem = NULL; - char *extra = ""; - for (linenum = 1; !problem && c < e; ++linenum) { - if (*c == '#') { - // skip comment lines - while (c < e && *c != '\n') - ++c; - } else if (*c == '\n') { - // skip empty lines - ++c; - } else if (c < e - 1 && *c == '\r' && c[1] == '\n') { - // skip empty lines - c += 2; - } else if (confc < MAX_CONFIG_VARS) { - char *var = confvar[confc] = c; - while (c < e && *c != '=' && *c != '\r' && *c != '\n') - ++c; - if (c < e && *c == '=') { - *c++ = '\0'; - if (is_configvarname(var)) { - confvalue[confc] = c; - while (c < e && *c != '\r' && *c != '\n') - ++c; - if (c < e && *c == '\n') { - *c++ = '\0'; - ++confc; - } else if (c < e - 1 && *c == '\r' && c[1] == '\n') { - *c++ = '\0'; - *c++ = '\0'; - ++confc; - } else { - problem = "missing end-of-line"; - } - } else { - problem = "invalid variable name: "; - extra = var; - } - } else { - problem = "missing '='"; - } - } else { - problem = "too many variables"; - } - } - if (problem) - return WHYF("Error in %s at line %u: %s%s", conffile, linenum, problem, extra); - return exists; + return metap->size != meta.size || metap->mtime != meta.mtime; } -static int read_config() +struct cf_om_node *cf_om_load() { - BUSY_BODY(int, -1, _read_config()); -} - -/* Return true if any conf...() function is in progress, ie, a configuration fetch function is being - * re-entered. This function allows other modules to avoid this re-entry, typically the logging - * system that uses confValueGet() to set itself up, which in turn can log messages. - * - * @author Andrew Bettison - */ -int confBusy() -{ - return busy; + int result = load(); + if (result == CFERROR) + return NULL; + return cf_om_root; } /* Check if the config file has changed since we last read it, and if so, invalidate the buffer so @@ -236,330 +136,90 @@ int confBusy() * * @author Andrew Bettison */ -static int _confReloadIfChanged() +struct cf_om_node *cf_om_reload() { - char conffile[1024]; - if (!FORM_SERVAL_INSTANCE_PATH(conffile, CONFFILE_NAME)) - return -1; - struct stat st; - if (stat(conffile, &st) == -1) { - if (errno != ENOENT) - return WHYF_perror("stat(%s)", conffile); - st.st_mtime = 0; + if (cf_om_root) { + if (!has_changed(&conffile_meta)) + return cf_om_root; + INFOF("config file %s -- detected new version", conffile_path()); } - if (config_timestamp != st.st_mtime) { - INFOF("detected new version of %s", conffile); - _read_config(); - return 1; - } - return 0; -} -int confReloadIfChanged() -{ - BUSY_BODY(int, -1, _confReloadIfChanged()); + return cf_om_load(); } -/* Return the number of config options. - * - * @author Andrew Bettison - */ -static int _confVarCount() +int cf_om_save(const struct cf_om_node *root) { - if (!config_buffer && _read_config() == -1) - return -1; - return confc; -} -int confVarCount() -{ - BUSY_BODY(int, -1, _confVarCount()); -} - -/* Return the string name of the config option with the given index, which must be in the range - * 0..confVarCount(). The returned pointer is only valid until the next call to confVar() or any - * other configuration query function. - * - * @author Andrew Bettison - */ -static const char *_confVar(unsigned int index) -{ - if (!config_buffer && _read_config() == -1) - return NULL; - if (index >= confc) { - WHYF("Config index=%u too big, confc=%u", index, confc); - return NULL; - } - return confvar[index]; -} -const char *confVar(unsigned int index) -{ - BUSY_BODY(const char *, NULL, _confVar(index)); -} - -/* Return the string value of the config option with the given index, which must be in the range - * 0..confVarCount(). The returned pointer is only valid until the next call to confVar() or any - * other configuration query function. - * - * @author Andrew Bettison - */ -static const char *_confValue(unsigned int index) -{ - if (!config_buffer && _read_config() == -1) - return NULL; - if (index >= confc) { - WHYF("Config index=%u too big, confc=%u", index, confc); - return NULL; - } - return confvalue[index]; -} -const char *confValue(unsigned int index) -{ - BUSY_BODY(const char *, NULL, _confValue(index)); -} - -/* Return the string value of the config option with the given name. The returned pointer is only - * valid until the next call to confVarCount(), confVar(), confValue() or any other configuration - * query function. If the named config option is not defined, then returns the given default value. - * If the named config option cannot be determined for any other reason, then logs the reason and - * returns the given default value. - * - * @author Andrew Bettison - */ -static const char *_confValueGet(const char *var, const char *defaultValue) -{ - if (var == NULL) { - WHYF("NULL var name, returning default value: %s", defaultValue ? defaultValue : "NULL"); - return defaultValue; - } - if (!config_buffer && _read_config() == -1) { - if (defaultValue) - WARNF("Config option %s: using default value: %s", var, defaultValue); - return defaultValue; - } - unsigned int i; - for (i = 0; i != confc; ++i) - if (strcasecmp(confvar[i], var) == 0) - return confvalue[i]; - return defaultValue; -} -const char *confValueGet(const char *var, const char *defaultValue) -{ - BUSY_BODY(const char *, defaultValue, _confValueGet(var, defaultValue)); -} - -static int _confValueGetBoolean(const char *var, int defaultValue) -{ - const char *value = _confValueGet(var, NULL); - if (!value) - return defaultValue; - int flag = confParseBoolean(value, var); - if (flag >= 0) - return flag; - WARNF("Config option %s: using default value %s", var, defaultValue ? "true" : "false"); - return defaultValue; -} -int confValueGetBoolean(const char *var, int defaultValue) -{ - BUSY_BODY(int, defaultValue, _confValueGetBoolean(var, defaultValue)); -} - -static int64_t _confValueGetInt64(const char *var, int64_t defaultValue) -{ - const char *start = _confValueGet(var, NULL); - if (!start) - return defaultValue; - const char *end = start; - long long value = strtoll(start, (char **)&end, 10); - if (*start && !*end && end != start) - return value; - WARNF("Config option %s: '%s' is not an integer, using default value %lld", var, start, (long long) defaultValue); - return defaultValue; -} -int64_t confValueGetInt64(const char *var, int64_t defaultValue) -{ - BUSY_BODY(int64_t, defaultValue, _confValueGetInt64(var, defaultValue)); -} - -static int64_t _confValueGetInt64Range(const char *var, int64_t defaultValue, int64_t rangemin, int64_t rangemax) -{ - int64_t value = _confValueGetInt64(var, defaultValue); - if (value >= rangemin || value <= rangemax) - return value; - WARNF("Config option %s: configured value %lld out of range [%lld,%lld], using default value %lld", - var, (long long) value, (long long) rangemin, (long long) rangemax, (long long) defaultValue); - return defaultValue; -} -int64_t confValueGetInt64Range(const char *var, int64_t defaultValue, int64_t rangemin, int64_t rangemax) -{ - BUSY_BODY(int64_t, defaultValue, _confValueGetInt64Range(var, defaultValue, rangemin, rangemax)); -} - -void confSetDebugFlags() -{ - if (config_buffer || read_config() != -1) { - debugflags_t setmask = 0; - debugflags_t clearmask = 0; - int setall = 0; - int clearall = 0; - unsigned int i; - for (i = 0; i != confc; ++i) { - char *var = confvar[i]; - if (strncasecmp(var, "debug.", 6) == 0) { - debugflags_t mask = debugFlagMask(var + 6); - if (mask == 0) - WARNF("Unsupported debug option '%s'", var); - else { - int flag = confParseBoolean(confvalue[i], var); - if (flag != -1) { - if (mask == DEBUG_ALL) { - if (flag) { - //DEBUGF("Set all debug flags"); - setall = 1; - } else { - //DEBUGF("Clear all debug flags"); - clearall = 1; - } - } else { - if (flag) { - //DEBUGF("Set %s", var); - setmask |= mask; - } else { - //DEBUGF("Clear %s", var); - clearmask |= mask; - } - } - } - } - } - } - if (setall) - debug = DEBUG_ALL; - else if (clearall) - debug = 0; - debug &= ~clearmask; - debug |= setmask; - } -} - -int confParseBoolean(const char *text, const char *option_name) -{ - if (!strcasecmp(text, "on") || !strcasecmp(text, "yes") || !strcasecmp(text, "true") || !strcmp(text, "1")) - return 1; - if (!strcasecmp(text, "off") || !strcasecmp(text, "no") || !strcasecmp(text, "false") || !strcmp(text, "0")) - return 0; - WARNF("Config option %s: invalid boolean value '%s'", option_name, text); - return -1; -} - -int confValueSet(const char *var, const char *value) -{ - INFOF("var=%s defaultValue=%s", - var ? alloca_str_toprint(var) : "NULL", - value ? alloca_str_toprint(value) : "NULL" - ); - if (!config_buffer && read_config() == -1) - return -1; - if (!is_configvarname(var)) - return WHYF("Cannot %s %s: invalid variable name", value ? "set" : "delete", var); - if (value == NULL) { - unsigned int i; - for (i = 0; i < confc; ++i) { - if (strcasecmp(var, confvar[i]) == 0) { - --confc; - for (; i < confc; ++i) { - confvar[i] = confvar[i + 1]; - confvalue[i] = confvalue[i + 1]; - } - return 0; - } - } - } else { - size_t valuelen = strlen(value); - unsigned int i; - for (i = 0; i != confc; ++i) { - if (strcasecmp(var, confvar[i]) == 0) { - char *valueptr = confvalue[i]; - if (valuelen > strlen(valueptr)) { - if ((valueptr = grow_config_buffer(valuelen + 1)) == NULL) - return -1; - } - strcpy(confvar[i], var); - confvalue[i] = strcpy(valueptr, value); - return 0; - } - } - if (confc >= MAX_CONFIG_VARS) - return WHYF("Cannot set %s: too many variables", var); - size_t varlen = strlen(var); - char *buf = grow_config_buffer(varlen + 1 + valuelen + 1); - if (buf == NULL) - return -1; - confvar[confc] = strcpy(buf, var); - confvalue[confc] = strcpy(buf + varlen + 1, value); - ++confc; - } - INFOF("config set %s = %s", var, value ? alloca_str_toprint(value) : "NULL"); - return 0; -} - -int confWrite() -{ - if (config_buffer) { - char conffile[1024]; + if (cf_om_root) { + const char *path = conffile_path(); char tempfile[1024]; FILE *outf = NULL; - if (!FORM_SERVAL_INSTANCE_PATH(conffile, "serval.conf")) - return -1; if (!FORM_SERVAL_INSTANCE_PATH(tempfile, "serval.conf.temp")) return -1; if ((outf = fopen(tempfile, "w")) == NULL) return WHYF_perror("fopen(%s, \"w\")", tempfile); - unsigned int i; - for (i = 0; i != confc; ++i) - fprintf(outf, "%s=%s\n", confvar[i], confvalue[i]); + struct cf_om_iterator it; + for (cf_om_iter_start(&it, root); it.node; cf_om_iter_next(&it)) + if (it.node->text) + fprintf(outf, "%s=%s\n", it.node->fullkey, it.node->text); if (fclose(outf) == EOF) return WHYF_perror("fclose(%s)", tempfile); - if (rename(tempfile, conffile)) { - WHYF_perror("rename(%s, %s)", tempfile, conffile); + if (rename(tempfile, path)) { + WHYF_perror("rename(%s, %s)", tempfile, path); unlink(tempfile); return -1; } - struct stat st; - if (stat(conffile, &st) == -1) - return WHYF_perror("stat(%s)", conffile); - config_timestamp = st.st_mtime; - INFOF("successfully wrote %s", conffile); + struct file_meta meta; + if (get_meta(path, &meta) == -1) + return -1; + INFOF("successfully wrote %s", path); + conffile_meta = meta; } return 0; } -static char *thisinstancepath = NULL; - -const char *serval_instancepath() +int cf_init() { - if (thisinstancepath) - return thisinstancepath; - const char *instancepath = getenv("SERVALINSTANCE_PATH"); - if (!instancepath) - instancepath = DEFAULT_INSTANCE_PATH; - return instancepath; + cf_limbo = 1; + return cf_dfl_config_main(&config) == CFERROR ? -1 : 0; } -void serval_setinstancepath(const char *instancepath) +int cf_load() { - if (thisinstancepath == NULL) - free(thisinstancepath); - - thisinstancepath = strdup(instancepath); + int result = CFOK; + if (cf_limbo) + result = cf_dfl_config_main(&config); + if (result == CFOK) { + result = load(); + if (result == CFOK) { + struct config_main new_config; + memset(&new_config, 0, sizeof new_config); + result = cf_dfl_config_main(&new_config); + if (result == CFOK) { + result = cf_om_root ? cf_opt_config_main(&new_config, cf_om_root) : CFEMPTY; + if (result == CFOK || result == CFEMPTY) { + config = new_config; + config_meta = conffile_meta; + cf_limbo = 0; + return 0; + } else if (result != CFERROR) { + config = new_config; + cf_limbo = 0; + WARN("limping along with incomplete configuration"); + } + } + } + } + cf_limbo = 0; // let log messages out + strbuf b = strbuf_alloca(180); + strbuf_cf_flag_reason(b, result); + return WHYF("config file %s not loaded -- %s", conffile_path(), strbuf_str(b)); } -int form_serval_instance_path(char *buf, size_t bufsiz, const char *path) +int cf_reload() { - if (snprintf(buf, bufsiz, "%s/%s", serval_instancepath(), path) < bufsiz) - return 1; - WHYF("Cannot form pathname \"%s/%s\" -- buffer too small (%lu bytes)", serval_instancepath(), path, (unsigned long)bufsiz); - return 0; -} - -int create_serval_instance_dir() { - return mkdirs(serval_instancepath(), 0700); + if (!cf_limbo && cf_om_root) { + if (!has_changed(&config_meta)) + return 0; + INFOF("config file %s reloading", conffile_path()); + } + return cf_load(); } diff --git a/conf.h b/conf.h index 06100913..25b12dc9 100644 --- a/conf.h +++ b/conf.h @@ -1,5 +1,6 @@ /* -Copyright (C) 2010-2012 Paul Gardner-Stephen, Serval Project. +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 @@ -16,42 +17,539 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include -#include -#include -#include -#include - -#ifdef ANDROID -#define DEFAULT_INSTANCE_PATH "/data/data/org.servalproject/var/serval-node" -#else -#define DEFAULT_INSTANCE_PATH "/var/serval-node" -#endif - -/* Handy statement for forming a path to an instance file in a char buffer whose declaration - * is in scope (so that sizeof(buf) will work). Evaluates to true if the pathname fitted into - * the provided buffer, false (0) otherwise (after logging an error). +/* This file defines the internal API to the configuration file. See "conf_schema.h" for the + * definition of the configuration schema, which is used to generate these API components. + * + * Each STRUCT(NAME, ...) schema declaration generates the following data declaration: + * + * struct config_NAME { + * ... + * }; + * + * A C struct definition containing exactly one element per schema declaration inside the + * STRUCT..END_STRUCT block, in the defined order. The TYPE and NAME of each element depends + * on the schema declaration that produces it: + * + * ATOM(TYPE, bar, ...) + * NODE(TYPE, bar, ...) + * + * TYPE bar; + * + * STRING(SIZE, bar, ...) + * + * char bar[SIZE+1]; + * + * SUB_STRUCT(NAME, bar, ...) + * NODE_STRUCT(NAME, bar, ...) + * + * struct config_NAME bar; + * + * Each ARRAY(NAME, ...) ... END_ARRAY(SIZE) schema declaration produces the following data + * declaration: + * + * struct config_NAME { + * unsigned ac; + * struct config_NAME__element { + * 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 key and a value: + * + * KEY_ATOM(TYPE, ...) + * + * TYPE key; + * + * KEY_STRING(SIZE, ...) + * + * char key[SIZE+1]; + * + * VALUE_ATOM(NAME, SIZE, LABELLEN, TYPE, ...) + * VALUE_NODE(NAME, SIZE, LABELLEN, TYPE, ...) + * + * TYPE value; + * + * VALUE_STRING(STRINGSIZE, ...) + * + * char value[STRINGSIZE+1]; + * + * VALUE_SUB_STRUCT(STRUCTNAME) + * VALUE_NODE_STRUCT(STRUCTNAME, ...) + * + * struct config_STRUCTNAME value; + * + * Each STRUCT(NAME, ...) and ARRAY(NAME, ...) schema declaration generates the following API + * functions: + * + * - int cf_dfl_config_NAME(struct config_NAME *dest); + * + * A C function which sets the entire contents of the given C structure to its default values + * as defined in the schema. This will only return CFOK or CFERROR; see below. + * + * - int cf_opt_config_NAME(struct config_NAME *dest, const struct cf_om_node *node); + * + * A C function which parses the given COM (configuration object model) and assigns the parsed + * result into the given C structure. See below for the return value. For arrays, this + * 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, FLAGS, 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); + * + * A C function which validates the contents of the given C structure (struct or array) as + * defined in the schema. This function is invoked by the cf_opt_config_NAME() parser function + * just before it returns, so all the parse functions have already been called and the result + * is assembled. The validator function is passed a pointer to the (non-const) structure, + * which it may modify if desired, and the original CFxxx flags result code (not CFERROR) that + * would be returned by the cf_opt_config_NAME() parser function. It returns a new CFxxx flags + * result (which may simply be the same as was passed). + * + * In the case arrays, validator() is passed a *dest containing elements that were successfully + * parsed from the COM, omitting any that did not parse successfully (in which case the + * relevant CFxxx result flags will be set) and arbitrarily omitting others that did not fit + * (in which case the CFOVERFLOW flag is set). It is up to validator() to decide whether to + * return some, all or none of these elements (ie, alter dest->ac and/or dest->av), and whether + * to set or clear the CFARRAYOVERFLOW bit, or set other bits (like CFINVALID for example). If + * there is no validator function, then cf_opt_config_NAME() will return an empty array (dest->ac + * == 0) in the case of CFARRAYOVERFLOW. + * + * All parse functions assign the result of their parsing into the struct given in their 'dest' + * argument, and return a bitmask of the following flags: + * + * - CFERROR (all bits set, == -1) if an unrecoverable error occurs (eg, malloc() fails). The + * result in *dest is undefined and may be malformed or inconsistent. + * + * - CFEMPTY if no items were parsed from the COM. In the case of a struct, this means that no + * child nodes were found for any elements; if any child nodes were present but failed parsing + * then CFEMPTY is not set but other flags will be set. In the case of arrays, CFEMPTY means + * that the returned array has zero length for _any_ reason (overflow, element parsing failures, + * or no elements present in the COM). + * + * - CFUNSUPPORTED if the config item (array or struct) is not supported. This flag is not + * produced by the normal cf_opt_config_NAME() parse functions, but a validation function could set + * it to indicate that a given option is not yet implemented or has been deprecated. In that + * case, the validation function should also log a message to that effect. The CFUNSUPPORTED + * flag is mainly used in its CFSUB(CFUNSUPPORTED) form (see below) to indicate that the COM + * contains elements that are not defined in the STRUCT. This may indicate a typo in the name + * of a config option, resulting in the intended option not being set. + * + * - CFDUPLICATE if a duplicate array entry was found. The result may be an empty array (in which + * case CFEMPTY is also set), or an array that omits the duplicate element. It is not defined + * which of the two conflicting elements will get omitted. Normal array parsing without a + * validator function will return an empty array in the case of duplicate, but a validator + * function may change this behaviour. + * + * - CFARRAYOVERFLOW if the size of any array was exceeded. The result in *dest may be empty (in + * which case CFEMPTY is also set), or may contain elements parsed successfully from the COM (ie, + * returned CFOK), omitting any that did not parse successfully (in which case the relevant + * CFSUB() bits will be set) and arbitrarily omitting others that did not fit. It is not defined + * which elements get omitted from an overflowed array. Normal array parsing without a validator + * function will return an empty array in the case of overflow, but a validator function may + * change this behaviour. + * + * - CFSTRINGFOVERFLOW if the size of any string element was exceeded. The result in *dest may be + * unchanged or may contain a truncated string, depending on the parser that detected and + * reported the string overflow. + * + * - CFINCOMPLETE if any MANDATORY element is missing (no node in the COM) or empty (as indicated + * by the CFEMPTY bit in its parse result). The result in *dest is valid but the missing + * mandatory element(s) are unchanged (in the case of a struct) or zero-length (in the case of an + * array). + * + * - CFINVALID if any invalid configuration value was encountered, ie, any parse function returned + * CFINVALID in its return flags. The result in *dest is valid and the elements that failed + * to parse are unchanged. + * + * - CFSUB(CFxxx) if any element of a STRUCT or ARRAY produced a CFxxx result when being parsed, ie + * any element's parse function returned CFxxx. In the case of a STRUCT, the failed elements are + * usually left with their prior (default) values, but this depends on the parse functions' + * behaviours. In the case of an ARRAY, failed elements are omitted from the array + * + * The difference between CFSUB(CFxxx) and CFxxx needs explaining. To illustrate, CFSUB(CFINVALID) + * is different from CFINVALID because an element of a struct or array may have failed to parse, yet + * the whole struct or array itself may still be valid (in the case of a struct, the element's prior + * value may be retained, and in the case of an array, the failed element is simply omitted from the + * result). A validator function may wish to reflect any CFSUB() bit as a CFINVALID result, but the + * normal behaviour of cf_opt_config_NAME() is to not return CFINVALID unless the validator function + * sets it. + * + * The special value CFOK is zero (no bits set); in this case a valid result is produced and all of + * *dest is overwritten (except unused array elements). + * + * @author Andrew Bettison */ -#define FORM_SERVAL_INSTANCE_PATH(buf, path) (form_serval_instance_path(buf, sizeof(buf), (path))) -int confBusy(); -int confReloadIfChanged(); -const char *confValueGet(const char *var, const char *defaultValue); -int confValueGetBoolean(const char *var, int defaultValue); -int64_t confValueGetInt64(const char *var, int64_t defaultValue); -int64_t confValueGetInt64Range(const char *var, int64_t defaultValue, int64_t rangemin, int64_t rangemax); -void confSetDebugFlags(); -int confParseBoolean(const char *text, const char *option_name); -int confValueSet(const char *var, const char *value); -int confWrite(); -int confVarCount(); -const char *confVar(unsigned int index); -const char *confValue(unsigned int index); -int form_serval_instance_path(char *buf, size_t bufsiz, const char *path); -const char *trimbuildpath(const char *s); -int mkdirs(const char *path, mode_t mode); -int mkdirsn(const char *path, size_t len, mode_t mode); -const char *serval_instancepath(); -void serval_setinstancepath(const char *instancepath); +#ifndef __SERVALDNA_CONFIG_H +#define __SERVALDNA_CONFIG_H +#include +#include + +#include "constants.h" +#include "strbuf.h" +#include "serval.h" +#include "rhizome.h" + +#define CONFIG_FILE_MAX_SIZE (32 * 1024) +#define INTERFACE_NAME_STRLEN 40 + +/* Return bit flags for config schema default cf_dfl_xxx() and parsing cf_opt_xxx() functions. */ + +#define CFERROR (~0) // all set +#define CFOK 0 +#define CFEMPTY (1<<0) +#define CFDUPLICATE (1<<1) +#define CFARRAYOVERFLOW (1<<2) +#define CFSTRINGOVERFLOW (1<<3) +#define CFINCOMPLETE (1<<4) +#define CFINVALID (1<<5) +#define CFUNSUPPORTED (1<<6) +#define CF__SUB_SHIFT 16 +#define CFSUB(f) ((f) << CF__SUB_SHIFT) +#define CF__SUBFLAGS CFSUB(~0) +#define CF__FLAGS (~0 & ~CF__SUBFLAGS) + +strbuf strbuf_cf_flags(strbuf, int); +strbuf strbuf_cf_flag_reason(strbuf sb, int flags); + +/* 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. + */ + +struct cf_om_node { + const char *source; // = parse_config() 'source' arg + unsigned int line_number; + const char *fullkey; // malloc() + const char *key; // points inside fullkey, do not free() + const char *text; // malloc() + size_t nodc; + struct cf_om_node *nodv[10]; // malloc() +}; + +int is_configvarname(const char *); +int cf_om_parse(const char *source, const char *buf, size_t len, struct cf_om_node **rootp); +int cf_om_get_child(const struct cf_om_node *parent, const char *key, const char *keyend); +const char *cf_om_get(const struct cf_om_node *root, const char *fullkey); +int cf_om_set(struct cf_om_node **nodep, const char *fullkey, const char *text); +void cf_om_free_node(struct cf_om_node **nodep); +void cf_om_dump_node(const struct cf_om_node *node, int indent); + +struct cf_om_iterator { + const struct cf_om_node *node; + unsigned sp; + struct { + const struct cf_om_node *node; + unsigned index; + } stack[20]; +}; + +void cf_om_iter_start(struct cf_om_iterator *, const struct cf_om_node *); +int cf_om_iter_next(struct cf_om_iterator *); + +struct cf_om_node *cf_om_load(); +struct cf_om_node *cf_om_reload(); +int cf_om_save(const struct cf_om_node *root); + +/* Diagnostic functions for use in config schema parsing functions, cf_opt_xxx(). */ + +void _cf_warn_nodev(struct __sourceloc __whence, const struct cf_om_node *node, const char *key, const char *fmt, va_list ap); +void _cf_warn_childrenv(struct __sourceloc __whence, const struct cf_om_node *parent, const char *fmt, va_list ap); +void _cf_warn_node(struct __sourceloc __whence, const struct cf_om_node *node, const char *key, const char *fmt, ...); +void _cf_warn_children(struct __sourceloc __whence, const struct cf_om_node *node, const char *fmt, ...); +void _cf_warn_duplicate_node(struct __sourceloc __whence, const struct cf_om_node *parent, const char *key); +void _cf_warn_missing_node(struct __sourceloc __whence, const struct cf_om_node *parent, const char *key); +void _cf_warn_node_value(struct __sourceloc __whence, const struct cf_om_node *node, int reason); +void _cf_warn_no_array(struct __sourceloc __whence, const struct cf_om_node *node, int reason); +void _cf_warn_unsupported_node(struct __sourceloc __whence, const struct cf_om_node *node); +void _cf_warn_unsupported_children(struct __sourceloc __whence, const struct cf_om_node *parent); +void _cf_warn_list_overflow(struct __sourceloc __whence, const struct cf_om_node *node); +void _cf_warn_spurious_children(struct __sourceloc __whence, const struct cf_om_node *parent); +void _cf_warn_array_key(struct __sourceloc __whence, const struct cf_om_node *node, int reason); +void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *node, int reason); + +#define cf_warn_nodev(node, key, fmt, ap) _cf_warn_nodev(__WHENCE__, node, key, fmt, ap) +#define cf_warn_childrenv(parent, fmt, ap) _cf_warn_childrenv(__WHENCE__, parent, fmt, ap) +#define cf_warn_node(node, key, fmt, ...) _cf_warn_node(__WHENCE__, node, key, fmt, ##__VA_ARGS__) +#define cf_warn_children(node, fmt, ...) _cf_warn_children(__WHENCE__, node, fmt, ##__VA_ARGS__) +#define cf_warn_duplicate_node(parent, key) _cf_warn_duplicate_node(__WHENCE__, parent, key) +#define cf_warn_missing_node(parent, key) _cf_warn_missing_node(__WHENCE__, parent, key) +#define cf_warn_node_value(node, reason) _cf_warn_node_value(__WHENCE__, node, reason) +#define cf_warn_no_array(node, reason) _cf_warn_no_array(__WHENCE__, node, reason) +#define cf_warn_unsupported_node(node) _cf_warn_unsupported_node(__WHENCE__, node) +#define cf_warn_unsupported_children(parent) _cf_warn_unsupported_children(__WHENCE__, parent) +#define cf_warn_list_overflow(node) _cf_warn_list_overflow(__WHENCE__, node) +#define cf_warn_spurious_children(parent) _cf_warn_spurious_children(__WHENCE__, parent) +#define cf_warn_array_key(node, reason) _cf_warn_array_key(__WHENCE__, node, reason) +#define cf_warn_array_value(node, reason) _cf_warn_array_value(__WHENCE__, node, reason) + +struct pattern_list { + unsigned patc; + char patv[16][INTERFACE_NAME_STRLEN + 1]; +}; + +#define PATTERN_LIST_EMPTY ((struct pattern_list){.patc = 0}) + +// Generate config struct definitions, struct config_NAME. +#define STRUCT(__name, __validator...) \ + struct config_##__name { +#define NODE(__type, __element, __default, __parser, __flags, __comment) \ + __type __element; +#define ATOM(__type, __element, __default, __parser, __flags, __comment) \ + __type __element; +#define STRING(__size, __element, __default, __parser, __flags, __comment) \ + char __element[__size + 1]; +#define SUB_STRUCT(__name, __element, __flags) \ + struct config_##__name __element; +#define NODE_STRUCT(__name, __element, __parser, __flags) \ + struct config_##__name __element; +#define END_STRUCT \ + }; +#define ARRAY(__name, __flags, __validator...) \ + struct config_##__name { \ + unsigned ac; \ + struct config_##__name##__element { +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + __type key; +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + 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)]; \ + }; +#include "conf_schema.h" +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 + +// Generate config set-default function prototypes, cf_dfl_config_NAME(). +#define STRUCT(__name, __validator...) \ + int cf_dfl_config_##__name(struct config_##__name *s); +#define NODE(__type, __element, __default, __parser, __flags, __comment) +#define ATOM(__type, __element, __default, __parser, __flags, __comment) +#define STRING(__size, __element, __default, __parser, __flags, __comment) +#define SUB_STRUCT(__name, __element, __flags) +#define NODE_STRUCT(__name, __element, __parser, __flags) +#define END_STRUCT +#define ARRAY(__name, __flags, __validator...) \ + int cf_dfl_config_##__name(struct config_##__name *a); +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) +#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 "conf_schema.h" +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 + +// Generate config parser function prototypes. +#define __VALIDATOR(__name, __validator...) \ + typedef int __validator_func__config_##__name##__t(const struct cf_om_node *, struct config_##__name *, int); \ + __validator_func__config_##__name##__t __dummy__validator_func__config_##__name, ##__validator; +#define STRUCT(__name, __validator...) \ + int cf_opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ + __VALIDATOR(__name, ##__validator) +#define NODE(__type, __element, __default, __parser, __flags, __comment) \ + int __parser(__type *, const struct cf_om_node *); +#define ATOM(__type, __element, __default, __parser, __flags, __comment) \ + int __parser(__type *, const char *); +#define STRING(__size, __element, __default, __parser, __flags, __comment) \ + int __parser(char *, size_t, const char *); +#define SUB_STRUCT(__name, __element, __flags) \ + int cf_opt_config_##__name(struct config_##__name *, const 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, __flags, __validator...) \ + int cf_opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ + __VALIDATOR(__name, ##__validator) +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + int __eltparser(__type *, const char *); +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + int __eltparser(char *, size_t, const char *); +#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 VALUE_SUB_STRUCT(__structname) \ + int cf_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 "conf_schema.h" +#undef __VALIDATOR +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 + +// Generate config array key comparison function prototypes. +#define STRUCT(__name, __validator...) +#define NODE(__type, __element, __default, __parser, __flags, __comment) +#define ATOM(__type, __element, __default, __parser, __flags, __comment) +#define STRING(__size, __element, __default, __parser, __flags, __comment) +#define SUB_STRUCT(__name, __element, __flags) +#define NODE_STRUCT(__name, __element, __parser, __flags) +#define END_STRUCT +#define ARRAY(__name, __flags, __validator...) \ + typedef int __compare_func__config_##__name##__t +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + (const __type *, const __type *); +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + (const char *, const char *); +#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 "conf_schema.h" +#undef ARRAY +#undef KEY_ATOM +#undef KEY_STRING +#define ARRAY(__name, __flags, __validator...) \ + __compare_func__config_##__name##__t __dummy__compare_func__config_##__name +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + ,##__cmpfunc; +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + ,##__cmpfunc; +#include "conf_schema.h" +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 + +// Generate config array search-by-key function prototypes. +#define STRUCT(__name, __validator...) +#define NODE(__type, __element, __default, __parser, __flags, __comment) +#define ATOM(__type, __element, __default, __parser, __flags, __comment) +#define STRING(__size, __element, __default, __parser, __flags, __comment) +#define SUB_STRUCT(__name, __element, __flags) +#define NODE_STRUCT(__name, __element, __parser, __flags) +#define END_STRUCT +#define ARRAY(__name, __flags, __validator...) \ + int config_##__name##__get(const struct config_##__name *, +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + const __type *); +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + const char *); +#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 "conf_schema.h" +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 cf_opt_boolean(int *booleanp, const char *text); +int cf_opt_absolute_path(char *str, size_t len, const char *text); +int cf_opt_debugflags(debugflags_t *flagsp, const struct cf_om_node *node); +int cf_opt_rhizome_peer(struct config_rhizome_peer *, const struct cf_om_node *node); +int cf_opt_rhizome_peer_from_uri(struct config_rhizome_peer *, const char *uri); +int cf_opt_str(char *str, size_t len, const char *text); +int cf_opt_str_nonempty(char *str, size_t len, const char *text); +int cf_opt_int(int *intp, const char *text); +int cf_opt_int32_nonneg(int32_t *intp, const char *text); +int cf_opt_uint32_nonzero(uint32_t *intp, const char *text); +int cf_opt_uint64_scaled(uint64_t *intp, const char *text); +int cf_opt_protocol(char *str, size_t len, const char *text); +int cf_opt_in_addr(struct in_addr *addrp, const char *text); +int cf_opt_port(unsigned short *portp, const char *text); +int cf_opt_sid(sid_t *sidp, const char *text); +int cf_opt_rhizome_bk(rhizome_bk_t *bkp, const char *text); +int cf_opt_interface_type(short *typep, const char *text); +int cf_opt_pattern_list(struct pattern_list *listp, const char *text); +int cf_opt_interface_list(struct config_interface_list *listp, const struct cf_om_node *node); + +extern int cf_limbo; +extern struct config_main config; + +int cf_init(); +int cf_load(); +int cf_reload(); + +#endif //__SERVALDNA_CONFIG_H diff --git a/conf_om.c b/conf_om.c index 6afeda51..3b098c44 100644 --- a/conf_om.c +++ b/conf_om.c @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "strbuf.h" #include "log.h" -#include "config.h" +#include "conf.h" static const char *cf_find_keyend(const char *const key, const char *const fullkeyend) { @@ -44,6 +44,34 @@ static const char *cf_find_keyend(const char *const key, const char *const fullk return s; } +/* This predicate function defines the constraints on configuration option names. + * Valid: + * foo + * foo.bar + * foo.bar.chow + * _word + * word1 + * word_1 + * Invalid: + * foo. + * .foo + * 1foo + * foo.bar. + * 12 + * 1.2.3 + * foo bar + * @author Andrew Bettison + */ +int is_configvarname(const char *text) +{ + const char *const textend = text + strlen(text); + const char *key = text; + const char *keyend = NULL; + while (key < textend && (keyend = cf_find_keyend(key, textend)) != NULL) + key = keyend + 1; + return keyend != NULL; +} + static int cf_om_make_child(struct cf_om_node **const parentp, const char *const fullkey, const char *const key, const char *const keyend) { // Allocate parent node if it is not present. @@ -95,23 +123,25 @@ static int cf_om_make_child(struct cf_om_node **const parentp, const char *const return i; } -int cf_get_child(const struct cf_om_node *parent, const char *key) +int cf_om_get_child(const struct cf_om_node *parent, const char *key, const char *keyend) { + if (keyend == NULL) + keyend = key + strlen(key); // TODO: use binary search, since child nodes are already sorted by key int i; for (i = 0; i < parent->nodc; ++i) - if (strcmp(parent->nodv[i]->key, key) == 0) + if (memcmp(parent->nodv[i]->key, key, keyend - key) == 0 && parent->nodv[i]->key[keyend - key] == '\0') return i; return -1; } -int cf_parse_to_om(const char *source, const char *buf, size_t len, struct cf_om_node **rootp) +int cf_om_parse(const char *source, const char *buf, size_t len, struct cf_om_node **rootp) { const char *end = buf + len; const char *line = buf; const char *nextline; unsigned lineno = 1; - int result = CFOK; + int result = CFEMPTY; for (lineno = 1; line < end; line = nextline, ++lineno) { const char *lend = line; while (lend < end && *lend != '\n') @@ -167,15 +197,16 @@ int cf_parse_to_om(const char *source, const char *buf, size_t len, struct cf_om return CFERROR; // out of memory node->source = source; node->line_number = lineno; + result &= ~CFEMPTY; } return result; } -void cf_free_node(struct cf_om_node **nodep) +void cf_om_free_node(struct cf_om_node **nodep) { if (*nodep) { while ((*nodep)->nodc) - cf_free_node(&(*nodep)->nodv[--(*nodep)->nodc]); + cf_om_free_node(&(*nodep)->nodv[--(*nodep)->nodc]); if ((*nodep)->fullkey) { free((char *)(*nodep)->fullkey); (*nodep)->fullkey = (*nodep)->key = NULL; @@ -189,7 +220,7 @@ void cf_free_node(struct cf_om_node **nodep) } } -void cf_dump_node(const struct cf_om_node *node, int indent) +void cf_om_dump_node(const struct cf_om_node *node, int indent) { if (node == NULL) DEBUGF("%*sNULL", indent * 3, ""); @@ -203,7 +234,95 @@ void cf_dump_node(const struct cf_om_node *node, int indent) ); int i; for (i = 0; i < node->nodc; ++i) - cf_dump_node(node->nodv[i], indent + 1); + cf_om_dump_node(node->nodv[i], indent + 1); + } +} + +const char *cf_om_get(const struct cf_om_node *node, const char *fullkey) +{ + const char *fullkeyend = fullkey + strlen(fullkey); + const char *key = fullkey; + const char *keyend = NULL; + int nodi = -1; + while (key <= fullkeyend && (keyend = cf_find_keyend(key, fullkeyend)) && (nodi = cf_om_get_child(node, key, keyend)) != -1) { + key = keyend + 1; + node = node->nodv[nodi]; + } + if (keyend == NULL) { + WARNF("malformed configuration option %s", alloca_toprint(-1, fullkey, fullkeyend - fullkey)); + return NULL; + } + if (nodi == -1) + return NULL; + return node->text; +} + +int cf_om_set(struct cf_om_node **nodep, const char *fullkey, const char *text) +{ + const char *fullkeyend = fullkey + strlen(fullkey); + const char *key = fullkey; + const char *keyend = NULL; + int nodi = -1; + while (key <= fullkeyend && (keyend = cf_find_keyend(key, fullkeyend)) && (nodi = cf_om_make_child(nodep, fullkey, key, keyend)) != -1) { + key = keyend + 1; + nodep = &(*nodep)->nodv[nodi]; + } + if (keyend == NULL) { + WARNF("malformed configuration option %s", alloca_toprint(-1, fullkey, fullkeyend - fullkey)); + return CFINVALID; + } + if (nodi == -1) + return CFERROR; // out of memory + struct cf_om_node *node = *nodep; + free((char *)node->text); + if (text == NULL) + node->text = NULL; + else if (!(node->text = str_edup(text))) + return CFERROR; // out of memory + return CFOK; +} + +void cf_om_iter_start(struct cf_om_iterator *it, const struct cf_om_node *root) +{ + it->sp = 0; + it->stack[0].node = it->node = root; + it->stack[0].index = 0; +} + +#if 0 +static void cf_om_iter_dump(struct cf_om_iterator *it) +{ + strbuf b = strbuf_alloca(1024); + strbuf_sprintf(b, "node=%p sp=%d", it->node, it->sp); + int i; + for (i = 0; i <= it->sp; ++i) + strbuf_sprintf(b, " %p[%d]", it->stack[i].node, it->stack[i].index); + DEBUG(strbuf_str(b)); +} +#endif + +int cf_om_iter_next(struct cf_om_iterator *it) +{ + //cf_om_iter_dump(it); + if (!it->node) + return 0; + while (1) { + const struct cf_om_node *parent = it->stack[it->sp].node; + int i = it->stack[it->sp].index++; + if (i < parent->nodc) { + it->node = parent->nodv[i]; + if (it->sp >= NELS(it->stack)) + return -1; + ++it->sp; + it->stack[it->sp].node = it->node; + it->stack[it->sp].index = 0; + return 0; + } else if (it->sp) { + --it->sp; + } else { + it->node = NULL; + return 0; + } } } diff --git a/conf_parse.c b/conf_parse.c index 8615246c..36e4bf3a 100644 --- a/conf_parse.c +++ b/conf_parse.c @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "log.h" -#include "config.h" +#include "conf.h" // Generate config set-default function definitions, cf_dfl_config_NAME(). #define STRUCT(__name, __validator...) \ @@ -133,7 +133,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. memset(used, 0, node->nodc * sizeof used[0]); #define __ITEM(__element, __flags, __parseexpr) \ { \ - int i = cf_get_child(node, #__element); \ + int i = cf_om_get_child(node, #__element, NULL); \ const struct cf_om_node *child = (i != -1) ? node->nodv[i] : NULL; \ int ret = CFEMPTY; \ if (child) { \ @@ -185,7 +185,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. result = (*validator)(node, strct, result); \ return result; \ } - #define ARRAY(__name, __flags, __validator...) \ int cf_opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \ int flags = (0 __flags); \ @@ -262,9 +261,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. __ARRAY_VALUE(cf_opt_config_##__structname(&array->av[n].value, child)) #define VALUE_NODE_STRUCT(__structname, __eltparser) \ __ARRAY_VALUE(__eltparser(&array->av[n].value, child)) - #include "conf_schema.h" - #undef STRUCT #undef NODE #undef ATOM @@ -281,3 +278,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #undef VALUE_SUB_STRUCT #undef VALUE_NODE_STRUCT #undef END_ARRAY + +// Generate config array search-by-key functions. +#define STRUCT(__name, __validator...) +#define NODE(__type, __element, __default, __parser, __flags, __comment) +#define ATOM(__type, __element, __default, __parser, __flags, __comment) +#define STRING(__size, __element, __default, __parser, __flags, __comment) +#define SUB_STRUCT(__name, __element, __flags) +#define NODE_STRUCT(__name, __element, __parser, __flags) +#define END_STRUCT +#define ARRAY(__name, __flags, __validator...) \ + int config_##__name##__get(const struct config_##__name *array, +#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ + const __type *key) { \ + int (*cmp)(const __type *, const __type *) = (NULL, ##__cmpfunc); \ + int i; \ + for (i = 0; i < array->ac; ++i) \ + if ((cmp ? (*cmp)(key, &array->av[i].key) : memcmp(key, &array->av[i].key, sizeof *key)) == 0) \ + return i; \ + return -1; \ + } +#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ + const char *key) { \ + int (*cmp)(const char *, const char *) = (NULL, ##__cmpfunc); \ + int i; \ + for (i = 0; i < array->ac; ++i) \ + if ((cmp ? (*cmp)(key, array->av[i].key) : strcmp(key, array->av[i].key)) == 0) \ + return i; \ + return -1; \ + } +#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 "conf_schema.h" +#undef STRUCT +#undef NODE +#undef ATOM +#undef STRING +#undef SUB_STRUCT +#undef NODE_STRUCT +#undef END_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 + diff --git a/conf_schema.c b/conf_schema.c index 58324b2a..17ad3459 100644 --- a/conf_schema.c +++ b/conf_schema.c @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "strbuf.h" #include "strbuf_helpers.h" -#include "config.h" +#include "conf.h" int cf_opt_boolean(int *booleanp, const char *text) { @@ -117,29 +117,34 @@ int cf_opt_protocol(char *str, size_t len, const char *text) return CFOK; } -int cf_opt_rhizome_peer(struct config_rhizomepeer *rpeer, const struct cf_om_node *node) +int cf_opt_rhizome_peer(struct config_rhizome_peer *rpeer, const struct cf_om_node *node) { if (!node->text) - return cf_opt_config_rhizomepeer(rpeer, node); + return cf_opt_config_rhizome_peer(rpeer, node); cf_warn_spurious_children(node); + return cf_opt_rhizome_peer_from_uri(rpeer, node->text); +} + +int cf_opt_rhizome_peer_from_uri(struct config_rhizome_peer *rpeer, const char *text) +{ const char *protocol; size_t protolen; const char *auth; - if (str_is_uri(node->text)) { + if (str_is_uri(text)) { const char *hier; - if (!( str_uri_scheme(node->text, &protocol, &protolen) - && str_uri_hierarchical(node->text, &hier, NULL) + if (!( str_uri_scheme(text, &protocol, &protolen) + && str_uri_hierarchical(text, &hier, NULL) && str_uri_hierarchical_authority(hier, &auth, NULL)) ) return CFINVALID; } else { - auth = node->text; + auth = text; protocol = "http"; protolen = strlen(protocol); } const char *host; size_t hostlen; - unsigned short port = 4110; + unsigned short port = RHIZOME_HTTP_PORT; if (!str_uri_authority_hostname(auth, &host, &hostlen)) return CFINVALID; str_uri_authority_port(auth, &port); @@ -179,10 +184,20 @@ int cf_opt_int(int *intp, const char *text) return CFOK; } +int cf_opt_int32_nonneg(int32_t *intp, const char *text) +{ + const char *end = text; + long value = strtol(text, (char**)&end, 10); + if (end == text || *end || value < 0 || value > 0x7fffffffL) + return CFINVALID; + *intp = value; + return CFOK; +} + int cf_opt_uint32_nonzero(uint32_t *intp, const char *text) { const char *end = text; - long value = strtoul(text, (char**)&end, 10); + unsigned long value = strtoul(text, (char**)&end, 10); if (end == text || *end || value < 1 || value > 0xffffffffL) return CFINVALID; *intp = value; @@ -286,7 +301,6 @@ int cf_opt_port(unsigned short *portp, const char *text) int cf_opt_sid(sid_t *sidp, const char *text) { - sid_t sid; if (!str_is_subscriber_id(text)) return CFINVALID; size_t n = fromhex(sidp->binary, text, SID_SIZE); @@ -296,7 +310,6 @@ int cf_opt_sid(sid_t *sidp, const char *text) int cf_opt_rhizome_bk(rhizome_bk_t *bkp, const char *text) { - rhizome_bk_t sid; if (!rhizome_str_is_bundle_key(text)) return CFINVALID; size_t n = fromhex(bkp->binary, text, RHIZOME_BUNDLE_KEY_BYTES); diff --git a/conf_schema.h b/conf_schema.h index 0c7d5c51..8784d103 100644 --- a/conf_schema.h +++ b/conf_schema.h @@ -204,10 +204,14 @@ KEY_ATOM(short, cf_opt_interface_type, cmp_short) VALUE_SUB_STRUCT(mdp_iftype) END_ARRAY(5) +STRUCT(mdp_selfannounce) +ATOM(uint32_t, ticks_per_full_address, 4, cf_opt_uint32_nonzero,, "Ticks to elapse between announcing full SID") +END_STRUCT + STRUCT(mdp) STRING(256, socket, DEFAULT_MDP_SOCKET_NAME, cf_opt_str_nonempty,, "Name of socket for MDP client interface") -ATOM(uint32_t, ticks_per_full_address, 4, cf_opt_uint32_nonzero,, "Ticks to elapse between announcing full SID") SUB_STRUCT(mdp_iftypelist, iftype,) +SUB_STRUCT(mdp_selfannounce,selfannounce,) END_STRUCT STRUCT(olsr) @@ -230,7 +234,7 @@ STRUCT(dna) SUB_STRUCT(executable, helper,) END_STRUCT -STRUCT(rhizomepeer) +STRUCT(rhizome_peer) STRING(25, protocol, "http", cf_opt_protocol,, "Protocol name") STRING(256, host, "", cf_opt_str_nonempty, MANDATORY, "Host name or IP address") ATOM(uint16_t, port, RHIZOME_HTTP_PORT, cf_opt_port,, "Port number") @@ -238,7 +242,7 @@ END_STRUCT ARRAY(peerlist,) KEY_STRING(15, cf_opt_str) -VALUE_NODE(struct config_rhizomepeer, cf_opt_rhizome_peer) +VALUE_NODE_STRUCT(rhizome_peer, cf_opt_rhizome_peer) END_ARRAY(10) STRUCT(rhizome_direct) @@ -249,7 +253,7 @@ STRUCT(rhizome_api_addfile) STRING(64, uri_path, "", cf_opt_absolute_path,, "URI path for HTTP add-file request") ATOM(struct in_addr, allow_host, (struct in_addr){htonl(INADDR_LOOPBACK)}, cf_opt_in_addr,, "IP address of host allowed to make HTTP add-file request") STRING(256, manifest_template_file, "", cf_opt_str_nonempty,, "Path of manifest template file, either absolute or relative to instance directory") -ATOM(sid_t, default_author, SID_NONE, cf_opt_sid,, "Author of add-file bundle if sender not given") +ATOM(sid_t, default_author, SID_ANY, cf_opt_sid,, "Author of add-file bundle if sender not given") ATOM(rhizome_bk_t, bundle_secret_key, RHIZOME_BK_NONE, cf_opt_rhizome_bk,, "Secret key of add-file bundle to try if sender not given") END_STRUCT @@ -259,7 +263,7 @@ END_STRUCT STRUCT(rhizome) ATOM(int, enable, 1, cf_opt_boolean,, "If true, Rhizome HTTP server is started") -STRING(256, datastore_path, "", cf_opt_absolute_path,, "Absolute path of rhizome storage directory") +STRING(256, datastore_path, "", cf_opt_absolute_path,, "Path of rhizome storage directory, absolute or relative to instance directory") ATOM(uint64_t, database_size, 1000000, cf_opt_uint64_scaled,, "Size of database in bytes") ATOM(uint32_t, fetch_delay_ms, 50, cf_opt_uint32_nonzero,, "Delay from receiving first bundle advert to initiating fetch") SUB_STRUCT(rhizome_direct, direct,) @@ -267,7 +271,7 @@ SUB_STRUCT(rhizome_api, api,) END_STRUCT STRUCT(directory) -ATOM(sid_t, service, SID_NONE, cf_opt_sid,, "Subscriber ID of Serval Directory Service") +ATOM(sid_t, service, SID_ANY, cf_opt_sid,, "Subscriber ID of Serval Directory Service") END_STRUCT STRUCT(host) @@ -284,10 +288,11 @@ END_ARRAY(32) STRUCT(network_interface) ATOM(int, exclude, 0, cf_opt_boolean,, "If true, do not use matching interfaces") ATOM(struct pattern_list, match, PATTERN_LIST_EMPTY, cf_opt_pattern_list, MANDATORY, "Names that match network interface") +STRING(256, dummy, "", cf_opt_str_nonempty,, "Path of dummy file, absolute or relative to server.dummy_interface_dir") ATOM(short, type, OVERLAY_INTERFACE_WIFI, cf_opt_interface_type,, "Type of network interface") ATOM(uint16_t, port, RHIZOME_HTTP_PORT, cf_opt_port,, "Port number for network interface") ATOM(uint64_t, speed, 1000000, cf_opt_uint64_scaled,, "Speed in bits per second") -ATOM(uint32_t, mdp_tick_ms, 0, cf_opt_uint32_nonzero,, "Override MDP tick interval for this interface") +ATOM(int, mdp_tick_ms, -1, cf_opt_int32_nonneg,, "Override MDP tick interval for this interface") END_STRUCT ARRAY(interface_list,) diff --git a/config.h b/config.h deleted file mode 100644 index c514df7f..00000000 --- a/config.h +++ /dev/null @@ -1,498 +0,0 @@ -/* -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. -*/ - -#ifndef __SERVALDNA_CONFIG_H -#define __SERVALDNA_CONFIG_H - -/* This file defines the internal API to the configuration file. See "conf_schema.h" for the - * definition of the configuration schema, which is used to generate these API components. - * - * Each STRUCT(NAME, ...) schema declaration generates the following data declaration: - * - * struct config_NAME { - * ... - * }; - * - * A C struct definition containing exactly one element per schema declaration inside the - * STRUCT..END_STRUCT block, in the defined order. The TYPE and NAME of each element depends - * on the schema declaration that produces it: - * - * ATOM(TYPE, bar, ...) - * NODE(TYPE, bar, ...) - * - * TYPE bar; - * - * STRING(SIZE, bar, ...) - * - * char bar[SIZE+1]; - * - * SUB_STRUCT(NAME, bar, ...) - * NODE_STRUCT(NAME, bar, ...) - * - * struct config_NAME bar; - * - * Each ARRAY(NAME, ...) ... END_ARRAY(SIZE) schema declaration produces the following data - * declaration: - * - * struct config_NAME { - * unsigned ac; - * struct config_NAME__element { - * 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 key and a value: - * - * KEY_ATOM(TYPE, ...) - * - * TYPE key; - * - * KEY_STRING(SIZE, ...) - * - * char key[SIZE+1]; - * - * VALUE_ATOM(NAME, SIZE, LABELLEN, TYPE, ...) - * VALUE_NODE(NAME, SIZE, LABELLEN, TYPE, ...) - * - * TYPE value; - * - * VALUE_STRING(STRINGSIZE, ...) - * - * char value[STRINGSIZE+1]; - * - * VALUE_SUB_STRUCT(STRUCTNAME) - * VALUE_NODE_STRUCT(STRUCTNAME, ...) - * - * struct config_STRUCTNAME value; - * - * Each STRUCT(NAME, ...) and ARRAY(NAME, ...) schema declaration generates the following API - * functions: - * - * - int cf_dfl_config_NAME(struct config_NAME *dest); - * - * A C function which sets the entire contents of the given C structure to its default values - * as defined in the schema. This will only return CFOK or CFERROR; see below. - * - * - int cf_opt_config_NAME(struct config_NAME *dest, const struct cf_om_node *node); - * - * A C function which parses the given COM (configuration object model) and assigns the parsed - * result into the given C structure. See below for the return value. For arrays, this - * 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, FLAGS, 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); - * - * A C function which validates the contents of the given C structure (struct or array) as - * defined in the schema. This function is invoked by the cf_opt_config_NAME() parser function - * just before it returns, so all the parse functions have already been called and the result - * is assembled. The validator function is passed a pointer to the (non-const) structure, - * which it may modify if desired, and the original CFxxx flags result code (not CFERROR) that - * would be returned by the cf_opt_config_NAME() parser function. It returns a new CFxxx flags - * result (which may simply be the same as was passed). - * - * In the case arrays, validator() is passed a *dest containing elements that were successfully - * parsed from the COM, omitting any that did not parse successfully (in which case the - * relevant CFxxx result flags will be set) and arbitrarily omitting others that did not fit - * (in which case the CFOVERFLOW flag is set). It is up to validator() to decide whether to - * return some, all or none of these elements (ie, alter dest->ac and/or dest->av), and whether - * to set or clear the CFARRAYOVERFLOW bit, or set other bits (like CFINVALID for example). If - * there is no validator function, then cf_opt_config_NAME() will return an empty array (dest->ac - * == 0) in the case of CFARRAYOVERFLOW. - * - * All parse functions assign the result of their parsing into the struct given in their 'dest' - * argument, and return a bitmask of the following flags: - * - * - CFERROR (all bits set, == -1) if an unrecoverable error occurs (eg, malloc() fails). The - * result in *dest is undefined and may be malformed or inconsistent. - * - * - CFEMPTY if no items were parsed from the COM. In the case of a struct, this means that no - * child nodes were found for any elements; if any child nodes were present but failed parsing - * then CFEMPTY is not set but other flags will be set. In the case of arrays, CFEMPTY means - * that the returned array has zero length for _any_ reason (overflow, element parsing failures, - * or no elements present in the COM). - * - * - CFUNSUPPORTED if the config item (array or struct) is not supported. This flag is not - * produced by the normal cf_opt_config_NAME() parse functions, but a validation function could set - * it to indicate that a given option is not yet implemented or has been deprecated. In that - * case, the validation function should also log a message to that effect. The CFUNSUPPORTED - * flag is mainly used in its CFSUB(CFUNSUPPORTED) form (see below) to indicate that the COM - * contains elements that are not defined in the STRUCT. This may indicate a typo in the name - * of a config option, resulting in the intended option not being set. - * - * - CFDUPLICATE if a duplicate array entry was found. The result may be an empty array (in which - * case CFEMPTY is also set), or an array that omits the duplicate element. It is not defined - * which of the two conflicting elements will get omitted. Normal array parsing without a - * validator function will return an empty array in the case of duplicate, but a validator - * function may change this behaviour. - * - * - CFARRAYOVERFLOW if the size of any array was exceeded. The result in *dest may be empty (in - * which case CFEMPTY is also set), or may contain elements parsed successfully from the COM (ie, - * returned CFOK), omitting any that did not parse successfully (in which case the relevant - * CFSUB() bits will be set) and arbitrarily omitting others that did not fit. It is not defined - * which elements get omitted from an overflowed array. Normal array parsing without a validator - * function will return an empty array in the case of overflow, but a validator function may - * change this behaviour. - * - * - CFSTRINGFOVERFLOW if the size of any string element was exceeded. The result in *dest may be - * unchanged or may contain a truncated string, depending on the parser that detected and - * reported the string overflow. - * - * - CFINCOMPLETE if any MANDATORY element is missing (no node in the COM) or empty (as indicated - * by the CFEMPTY bit in its parse result). The result in *dest is valid but the missing - * mandatory element(s) are unchanged (in the case of a struct) or zero-length (in the case of an - * array). - * - * - CFINVALID if any invalid configuration value was encountered, ie, any parse function returned - * CFINVALID in its return flags. The result in *dest is valid and the elements that failed - * to parse are unchanged. - * - * - CFSUB(CFxxx) if any element of a STRUCT or ARRAY produced a CFxxx result when being parsed, ie - * any element's parse function returned CFxxx. In the case of a STRUCT, the failed elements are - * usually left with their prior (default) values, but this depends on the parse functions' - * behaviours. In the case of an ARRAY, failed elements are omitted from the array - * - * The difference between CFSUB(CFxxx) and CFxxx needs explaining. To illustrate, CFSUB(CFINVALID) - * is different from CFINVALID because an element of a struct or array may have failed to parse, yet - * the whole struct or array itself may still be valid (in the case of a struct, the element's prior - * value may be retained, and in the case of an array, the failed element is simply omitted from the - * result). A validator function may wish to reflect any CFSUB() bit as a CFINVALID result, but the - * normal behaviour of cf_opt_config_NAME() is to not return CFINVALID unless the validator function - * sets it. - * - * The special value CFOK is zero (no bits set); in this case a valid result is produced and all of - * *dest is overwritten (except unused array elements). - * - * @author Andrew Bettison - */ - -#include -#include - -#include "constants.h" -#include "strbuf.h" - -#define NELS(a) (sizeof (a) / sizeof *(a)) - -#define RHIZOME_BUNDLE_KEY_BYTES 32 - -#define PORT_DNA 4110 -#define RHIZOME_HTTP_PORT 4110 - -typedef struct sid_binary { unsigned char binary[SID_SIZE]; } sid_t; -#define SID_NONE ((sid_t){0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}) -#define SID_BROADCAST ((sid_t){0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}) - -typedef struct rhizome_bk_binary { unsigned char binary[RHIZOME_BUNDLE_KEY_BYTES]; } rhizome_bk_t; -#define RHIZOME_BK_NONE ((rhizome_bk_t){0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}) - -#define INTERFACE_NAME_STRLEN 40 -struct pattern_list { - unsigned patc; - char patv[16][INTERFACE_NAME_STRLEN + 1]; -}; -#define PATTERN_LIST_EMPTY ((struct pattern_list){.patc = 0}) - -/* Return bit flags for config schema default cf_dfl_xxx() and parsing cf_opt_xxx() functions. */ - -#define CFERROR (~0) // all set -#define CFOK 0 -#define CFEMPTY (1<<0) -#define CFDUPLICATE (1<<1) -#define CFARRAYOVERFLOW (1<<2) -#define CFSTRINGOVERFLOW (1<<3) -#define CFINCOMPLETE (1<<4) -#define CFINVALID (1<<5) -#define CFUNSUPPORTED (1<<6) -#define CF__SUB_SHIFT 16 -#define CFSUB(f) ((f) << CF__SUB_SHIFT) -#define CF__SUBFLAGS CFSUB(~0) -#define CF__FLAGS (~0 & ~CF__SUBFLAGS) - -strbuf strbuf_cf_flags(strbuf, int); -strbuf strbuf_cf_flag_reason(strbuf sb, int flags); - -/* 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. - */ - -struct cf_om_node { - const char *source; // = parse_config() 'source' arg - unsigned int line_number; - const char *fullkey; // malloc() - const char *key; // points inside fullkey, do not free() - const char *text; // malloc() - size_t nodc; - struct cf_om_node *nodv[10]; // malloc() -}; - -int cf_parse_to_om(const char *source, const char *buf, size_t len, struct cf_om_node **rootp); -int cf_get_child(const struct cf_om_node *parent, const char *key); -void cf_free_node(struct cf_om_node **nodep); -void cf_dump_node(const struct cf_om_node *node, int indent); - -/* Diagnostic functions for use in config schema parsing functions, cf_opt_xxx(). */ - -void _cf_warn_nodev(struct __sourceloc __whence, const struct cf_om_node *node, const char *key, const char *fmt, va_list ap); -void _cf_warn_childrenv(struct __sourceloc __whence, const struct cf_om_node *parent, const char *fmt, va_list ap); -void _cf_warn_node(struct __sourceloc __whence, const struct cf_om_node *node, const char *key, const char *fmt, ...); -void _cf_warn_children(struct __sourceloc __whence, const struct cf_om_node *node, const char *fmt, ...); -void _cf_warn_duplicate_node(struct __sourceloc __whence, const struct cf_om_node *parent, const char *key); -void _cf_warn_missing_node(struct __sourceloc __whence, const struct cf_om_node *parent, const char *key); -void _cf_warn_node_value(struct __sourceloc __whence, const struct cf_om_node *node, int reason); -void _cf_warn_no_array(struct __sourceloc __whence, const struct cf_om_node *node, int reason); -void _cf_warn_unsupported_node(struct __sourceloc __whence, const struct cf_om_node *node); -void _cf_warn_unsupported_children(struct __sourceloc __whence, const struct cf_om_node *parent); -void _cf_warn_list_overflow(struct __sourceloc __whence, const struct cf_om_node *node); -void _cf_warn_spurious_children(struct __sourceloc __whence, const struct cf_om_node *parent); -void _cf_warn_array_key(struct __sourceloc __whence, const struct cf_om_node *node, int reason); -void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *node, int reason); - -#define cf_warn_nodev(node, key, fmt, ap) _cf_warn_nodev(__WHENCE__, node, key, fmt, ap) -#define cf_warn_childrenv(parent, fmt, ap) _cf_warn_childrenv(__WHENCE__, parent, fmt, ap) -#define cf_warn_node(node, key, fmt, ...) _cf_warn_node(__WHENCE__, node, key, fmt, ##__VA_ARGS__) -#define cf_warn_children(node, fmt, ...) _cf_warn_children(__WHENCE__, node, fmt, ##__VA_ARGS__) -#define cf_warn_duplicate_node(parent, key) _cf_warn_duplicate_node(__WHENCE__, parent, key) -#define cf_warn_missing_node(parent, key) _cf_warn_missing_node(__WHENCE__, parent, key) -#define cf_warn_node_value(node, reason) _cf_warn_node_value(__WHENCE__, node, reason) -#define cf_warn_no_array(node, reason) _cf_warn_no_array(__WHENCE__, node, reason) -#define cf_warn_unsupported_node(node) _cf_warn_unsupported_node(__WHENCE__, node) -#define cf_warn_unsupported_children(parent) _cf_warn_unsupported_children(__WHENCE__, parent) -#define cf_warn_list_overflow(node) _cf_warn_list_overflow(__WHENCE__, node) -#define cf_warn_spurious_children(parent) _cf_warn_spurious_children(__WHENCE__, parent) -#define cf_warn_array_key(node, reason) _cf_warn_array_key(__WHENCE__, node, reason) -#define cf_warn_array_value(node, reason) _cf_warn_array_value(__WHENCE__, node, reason) - -// Generate config struct definitions, struct config_NAME. -#define STRUCT(__name, __validator...) \ - struct config_##__name { -#define NODE(__type, __element, __default, __parser, __flags, __comment) \ - __type __element; -#define ATOM(__type, __element, __default, __parser, __flags, __comment) \ - __type __element; -#define STRING(__size, __element, __default, __parser, __flags, __comment) \ - char __element[__size + 1]; -#define SUB_STRUCT(__name, __element, __flags) \ - struct config_##__name __element; -#define NODE_STRUCT(__name, __element, __parser, __flags) \ - struct config_##__name __element; -#define END_STRUCT \ - }; -#define ARRAY(__name, __flags, __validator...) \ - struct config_##__name { \ - unsigned ac; \ - struct config_##__name##__element { -#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ - __type key; -#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ - 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)]; \ - }; -#include "conf_schema.h" -#undef STRUCT -#undef NODE -#undef ATOM -#undef STRING -#undef SUB_STRUCT -#undef NODE_STRUCT -#undef END_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 - -// Generate config set-default function prototypes, cf_dfl_config_NAME(). -#define STRUCT(__name, __validator...) \ - int cf_dfl_config_##__name(struct config_##__name *s); -#define NODE(__type, __element, __default, __parser, __flags, __comment) -#define ATOM(__type, __element, __default, __parser, __flags, __comment) -#define STRING(__size, __element, __default, __parser, __flags, __comment) -#define SUB_STRUCT(__name, __element, __flags) -#define NODE_STRUCT(__name, __element, __parser, __flags) -#define END_STRUCT -#define ARRAY(__name, __flags, __validator...) \ - int cf_dfl_config_##__name(struct config_##__name *a); -#define KEY_ATOM(__type, __eltparser, __cmpfunc...) -#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) -#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 "conf_schema.h" -#undef STRUCT -#undef NODE -#undef ATOM -#undef STRING -#undef SUB_STRUCT -#undef NODE_STRUCT -#undef END_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 - -// Generate config parser function prototypes. -#define __VALIDATOR(__name, __validator...) \ - typedef int __validator_func__config_##__name##__t(const struct cf_om_node *, struct config_##__name *, int); \ - __validator_func__config_##__name##__t __dummy__validator_func__config_##__name, ##__validator; -#define STRUCT(__name, __validator...) \ - int cf_opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ - __VALIDATOR(__name, ##__validator) -#define NODE(__type, __element, __default, __parser, __flags, __comment) \ - int __parser(__type *, const struct cf_om_node *); -#define ATOM(__type, __element, __default, __parser, __flags, __comment) \ - int __parser(__type *, const char *); -#define STRING(__size, __element, __default, __parser, __flags, __comment) \ - int __parser(char *, size_t, const char *); -#define SUB_STRUCT(__name, __element, __flags) \ - int cf_opt_config_##__name(struct config_##__name *, const 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, __flags, __validator...) \ - int cf_opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ - __VALIDATOR(__name, ##__validator) -#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ - int __eltparser(__type *, const char *); -#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ - int __eltparser(char *, size_t, const char *); -#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 VALUE_SUB_STRUCT(__structname) \ - int cf_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 "conf_schema.h" -#undef __VALIDATOR -#undef STRUCT -#undef NODE -#undef ATOM -#undef STRING -#undef SUB_STRUCT -#undef NODE_STRUCT -#undef END_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 - -// Generate config array key comparison function prototypes. -#define STRUCT(__name, __validator...) -#define NODE(__type, __element, __default, __parser, __flags, __comment) -#define ATOM(__type, __element, __default, __parser, __flags, __comment) -#define STRING(__size, __element, __default, __parser, __flags, __comment) -#define SUB_STRUCT(__name, __element, __flags) -#define NODE_STRUCT(__name, __element, __parser, __flags) -#define END_STRUCT -#define ARRAY(__name, __flags, __validator...) \ - typedef int __compare_func__config_##__name##__t -#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ - (const __type *, const __type *); -#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ - (const char *, const char *); -#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 "conf_schema.h" -#undef ARRAY -#undef KEY_ATOM -#undef KEY_STRING -#define ARRAY(__name, __flags, __validator...) \ - __compare_func__config_##__name##__t __dummy__compare_func__config_##__name -#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \ - ,##__cmpfunc; -#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \ - ,##__cmpfunc; -#include "conf_schema.h" -#undef STRUCT -#undef NODE -#undef ATOM -#undef STRING -#undef SUB_STRUCT -#undef NODE_STRUCT -#undef END_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 cf_opt_boolean(int *booleanp, const char *text); -int cf_opt_absolute_path(char *str, size_t len, const char *text); -int cf_opt_debugflags(debugflags_t *flagsp, const struct cf_om_node *node); -int cf_opt_rhizome_peer(struct config_rhizomepeer *, const struct cf_om_node *node); -int cf_opt_str(char *str, size_t len, const char *text); -int cf_opt_str_nonempty(char *str, size_t len, const char *text); -int cf_opt_int(int *intp, const char *text); -int cf_opt_uint32_nonzero(uint32_t *intp, const char *text); -int cf_opt_uint64_scaled(uint64_t *intp, const char *text); -int cf_opt_protocol(char *str, size_t len, const char *text); -int cf_opt_in_addr(struct in_addr *addrp, const char *text); -int cf_opt_port(unsigned short *portp, const char *text); -int cf_opt_sid(sid_t *sidp, const char *text); -int cf_opt_rhizome_bk(rhizome_bk_t *bkp, const char *text); -int cf_opt_interface_type(short *typep, const char *text); -int cf_opt_pattern_list(struct pattern_list *listp, const char *text); -int cf_opt_interface_list(struct config_interface_list *listp, const struct cf_om_node *node); - -#endif //__SERVALDNA_CONFIG_H diff --git a/constants.h b/constants.h index ab2ca433..95997873 100644 --- a/constants.h +++ b/constants.h @@ -19,6 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __SERVALD_CONSTANTS_H #define __SERVALD_CONSTANTS_H +#define NELS(a) (sizeof (a) / sizeof *(a)) + /* Packet format: 16 bit - Magic value 0x4110 diff --git a/directory_client.c b/directory_client.c index f67ba222..9454e4c1 100644 --- a/directory_client.c +++ b/directory_client.c @@ -15,6 +15,7 @@ #include "serval.h" #include "str.h" #include "overlay_address.h" +#include "conf.h" struct subscriber *directory_service; @@ -77,18 +78,9 @@ static void directory_send_keyring(struct subscriber *directory_service){ static int load_directory_config(){ if (!directory_service){ - const char *sid_hex = confValueGet("directory.service", NULL); - if (!sid_hex) - return 0; - - unsigned char sid[SID_SIZE]; - if (stowSid(sid, 0, sid_hex)==-1) - return WHYF("Invalid directory server SID %s", sid_hex); - - directory_service = find_subscriber(sid, SID_SIZE, 1); + directory_service = find_subscriber(config.directory.service.binary, SID_SIZE, 1); if (!directory_service) return WHYF("Failed to create subscriber record"); - // used by tests INFOF("ADD DIRECTORY SERVICE %s", alloca_tohex_sid(directory_service->sid)); } diff --git a/dna_helper.c b/dna_helper.c index fc02bac9..fdd73fa6 100644 --- a/dna_helper.c +++ b/dna_helper.c @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include "serval.h" +#include "conf.h" #include "str.h" #include "strbuf.h" #include "strbuf_helpers.h" @@ -148,9 +149,7 @@ dna_helper_close_pipes() int dna_helper_start() { - const char *command = confValueGet("dna.helper.executable", NULL); - const char *arg = confValueGet("dna.helper.argv.1", NULL); - if (!command || !command[0]) { + if (!config.dna.helper.executable[0]) { /* Check if we have a helper configured. If not, then set dna_helper_pid to magic value of 0 so that we don't waste time in future looking up the dna helper configuration value. */ @@ -182,7 +181,14 @@ dna_helper_start() close(stdout_fds[1]); return -1; } - + // Construct argv[] for execv() and log messages. + const char *argv[config.dna.helper.argv.ac + 2]; + argv[0] = config.dna.helper.executable; + int i; + for (i = 0; i < config.dna.helper.argv.ac; ++i) + argv[i + 1] = config.dna.helper.argv.av[i].value; + argv[i] = NULL; + strbuf argv_sb = strbuf_append_argv(strbuf_alloca(1024), config.dna.helper.argv.ac + 2, argv); switch (dna_helper_pid = fork()) { case 0: /* Child, should exec() to become helper after installing file descriptors. */ @@ -197,11 +203,14 @@ dna_helper_start() fflush(stderr); _exit(-1); } - /* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't - * see it as a sentinal */ - execl(command, command, arg, (void *)NULL); - LOGF_perror(LOG_LEVEL_FATAL, "execl(%s, %s, %s, NULL)", command, command, arg ? arg : "NULL"); - fflush(stderr); + { + execv(config.dna.helper.executable, (char **)argv); + LOGF_perror(LOG_LEVEL_FATAL, "execl(%s, [%s])", + alloca_str_toprint(config.dna.helper.executable), + strbuf_str(argv_sb) + ); + fflush(stderr); + } do { _exit(-1); } while (1); break; case -1: @@ -223,13 +232,13 @@ dna_helper_start() dna_helper_stdin = stdin_fds[1]; dna_helper_stdout = stdout_fds[0]; dna_helper_stderr = stderr_fds[0]; - INFOF("STARTED DNA HELPER pid=%u stdin=%d stdout=%d stderr=%d executable=%s arg=%s", + INFOF("STARTED DNA HELPER pid=%u stdin=%d stdout=%d stderr=%d executable=%s argv=[%s]", dna_helper_pid, dna_helper_stdin, dna_helper_stdout, dna_helper_stderr, - command, - arg ? arg : "NULL" + alloca_str_toprint(config.dna.helper.executable), + strbuf_str(argv_sb) ); sched_requests.function = monitor_requests; sched_requests.context = NULL; diff --git a/headerfiles.mk b/headerfiles.mk index 6b955bab..e39ea027 100644 --- a/headerfiles.mk +++ b/headerfiles.mk @@ -12,6 +12,7 @@ HDRS= fifo.h \ strbuf_helpers.h \ sha2.h \ conf.h \ + conf_schema.h \ crypto.h \ log.h \ net.h \ diff --git a/instance.c b/instance.c new file mode 100644 index 00000000..85122f28 --- /dev/null +++ b/instance.c @@ -0,0 +1,57 @@ +/* +Serval DNA instance directory path +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. +*/ + +#include +#include "serval.h" +#include "os.h" +#include "strbuf.h" +#include "strbuf_helpers.h" + +static char *thisinstancepath = NULL; + +const char *serval_instancepath() +{ + if (thisinstancepath) + return thisinstancepath; + const char *instancepath = getenv("SERVALINSTANCE_PATH"); + if (!instancepath) + instancepath = DEFAULT_INSTANCE_PATH; + return instancepath; +} + +void serval_setinstancepath(const char *instancepath) +{ + if (thisinstancepath == NULL) + free(thisinstancepath); + thisinstancepath = strdup(instancepath); +} + +int form_serval_instance_path(char *buf, size_t bufsiz, const char *path) +{ + strbuf b = strbuf_local(buf, bufsiz); + strbuf_path_join(b, serval_instancepath(), path, NULL); + if (!strbuf_overrun(b)) + return 1; + WHYF("Cannot form pathname \"%s/%s\" -- buffer too small (%lu bytes)", serval_instancepath(), path, (unsigned long)bufsiz); + return 0; +} + +int create_serval_instance_dir() { + return mkdirs(serval_instancepath(), 0700); +} diff --git a/log.c b/log.c index a45a129b..1be0b87f 100644 --- a/log.c +++ b/log.c @@ -46,8 +46,6 @@ const struct __sourceloc __whence = __NOWHERE__; debugflags_t debug = 0; static FILE *logfile = NULL; -static int flag_show_pid = -1; -static int flag_show_time = -1; /* The logbuf is used to accumulate log messages before the log file is open and ready for writing. @@ -78,11 +76,11 @@ static FILE *_open_logging() if (!logfile) { const char *logpath = getenv("SERVALD_LOG_FILE"); if (!logpath) { - if (confBusy()) + if (cf_limbo) return NULL; - logpath = confValueGet("log.file", NULL); + logpath = config.log.file; } - if (!logpath) { + if (!logpath || !logpath[0]) { logfile = stderr; //fopen("/tmp/foo", "a"); INFO("No logfile configured -- logging to stderr"); } else if ((logfile = fopen(logpath, "a"))) { @@ -102,20 +100,6 @@ FILE *open_logging() return _open_logging(); } -static int show_pid() -{ - if (flag_show_pid < 0 && !confBusy()) - flag_show_pid = confValueGetBoolean("log.show_pid", 0); - return flag_show_pid; -} - -static int show_time() -{ - if (flag_show_time < 0 && !confBusy()) - flag_show_time = confValueGetBoolean("log.show_time", 0); - return flag_show_time; -} - void close_logging() { if (logfile) { @@ -144,10 +128,8 @@ static int _log_prepare(int level, struct __sourceloc whence) return 0; struct timeval tv; tv.tv_sec = 0; - int showtime = show_time(); - if (showtime) + if (config.log.show_time) gettimeofday(&tv, NULL); - int showpid = show_pid(); _open_logging(); // Put initial INFO message at start of log file // No calls outside log.c from this point on. if (strbuf_is_empty(&logbuf)) @@ -165,9 +147,9 @@ static int _log_prepare(int level, struct __sourceloc whence) } strbuf_sprintf(&logbuf, "%-6.6s ", levelstr); #endif - if (showpid) + if (config.log.show_pid) strbuf_sprintf(&logbuf, "[%5u] ", getpid()); - if (showtime) { + if (config.log.show_time) { if (tv.tv_sec == 0) { strbuf_puts(&logbuf, "NOTIME______ "); } else { diff --git a/main.c b/main.c index 041da7aa..501e60b2 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "conf.h" int main(int argc, char **argv) { @@ -31,6 +32,7 @@ int main(int argc, char **argv) srandomdev(); server_save_argv(argc, (const char*const*)argv); + cf_init(); int status = parseCommandLine(argv[0], argc - 1, (const char*const*)&argv[1]); #if defined WIN32 WSACleanup(); diff --git a/monitor-client.c b/monitor-client.c index 5f276d8e..16630540 100644 --- a/monitor-client.c +++ b/monitor-client.c @@ -73,14 +73,14 @@ int monitor_socket_name(struct sockaddr_un *name){ hanging around. */ name->sun_path[0] = '\0'; /* XXX: 104 comes from OSX sys/un.h - no #define (note Linux has UNIX_PATH_MAX and it's 108(!)) */ - snprintf(&name->sun_path[1],104-2,"%s", - confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME)); + snprintf(&name->sun_path[1],104-2,"%s", config.monitor.socket); /* Doesn't include trailing nul */ len = 1+strlen(&name->sun_path[1]) + sizeof(name->sun_family); #else snprintf(name->sun_path,104-1,"%s/%s", serval_instancepath(), - confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME)); + config.monitor.socket + ); /* Includes trailing nul */ len = 1+strlen(name->sun_path) + sizeof(name->sun_family); #endif diff --git a/monitor.c b/monitor.c index 81455fba..9bbca5a9 100644 --- a/monitor.c +++ b/monitor.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" +#include "conf.h" #include "rhizome.h" #include "cli.h" #include "str.h" @@ -339,8 +340,7 @@ static void monitor_new_client(int s) { #endif if (otheruid != getuid()) { - int allowed_id = confValueGetInt64("monitor.uid",-1); - if (otheruid != allowed_id){ + if (otheruid != config.monitor.uid){ WHYF("monitor.socket client has wrong uid (%d versus %d)", otheruid,getuid()); write_str(s, "\nCLOSE:Incorrect UID\n"); goto error; diff --git a/overlay_address.c b/overlay_address.c index 6584b314..145a3e1b 100644 --- a/overlay_address.c +++ b/overlay_address.c @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "conf.h" #include "str.h" #include "overlay_address.h" #include "overlay_buffer.h" @@ -267,36 +268,19 @@ int reachable_unicast(struct subscriber *subscriber, overlay_interface *interfac } // load a unicast address from configuration, replace with database?? -int load_subscriber_address(struct subscriber *subscriber){ - char buff[80]; - const char *sid_hex = alloca_tohex_sid(subscriber->sid); - - snprintf(buff, sizeof(buff), "%s.interface", sid_hex); - const char *interface_name = confValueGet(buff, NULL); - // no unicast configuration? just return. - if (!interface_name) +int load_subscriber_address(struct subscriber *subscriber) +{ + int i = config_host_list__get(&config.hosts, (const sid_t*)subscriber->sid); + // No unicast configuration? just return. + if (i == -1) return 1; - - snprintf(buff, sizeof(buff), "%s.address", sid_hex); - const char *address = confValueGet(buff, NULL); - if (!address) - return 1; - - snprintf(buff, sizeof(buff), "%s.port", sid_hex); - int port = confValueGetInt64Range(buff, PORT_DNA, 1, 65535); - - overlay_interface *interface = overlay_interface_find_name(interface_name); + const struct config_host *hostc = &config.hosts.av[i].value; + overlay_interface *interface = overlay_interface_find_name(hostc->interface); if (!interface){ - WARNF("Interface %s is not UP", interface_name); + WARNF("Interface %s is not UP", hostc->interface); return -1; } - - struct in_addr addr; - if (!inet_aton(address, &addr)){ - return WHYF("%s doesn't look like an IP address", address); - } - - return reachable_unicast(subscriber, interface, addr, port); + return reachable_unicast(subscriber, interface, hostc->address, hostc->port); } // generate a new random broadcast address @@ -374,24 +358,16 @@ int overlay_address_append(struct overlay_buffer *b, struct subscriber *subscrib return 0; } -int overlay_address_append_self(overlay_interface *interface, struct overlay_buffer *b){ - static int ticks_per_full_address = -1; - if (ticks_per_full_address == -1) { - ticks_per_full_address = confValueGetInt64Range("mdp.selfannounce.ticks_per_full_address", 4LL, 1LL, 1000000LL); - INFOF("ticks_per_full_address = %d", ticks_per_full_address); - } - +int overlay_address_append_self(overlay_interface *interface, struct overlay_buffer *b) +{ if (!my_subscriber) return WHY("I don't know who I am yet"); - - if (++interface->ticks_since_sent_full_address > ticks_per_full_address){ + if (++interface->ticks_since_sent_full_address > config.mdp.selfannounce.ticks_per_full_address) { interface->ticks_since_sent_full_address = 0; my_subscriber->send_full=1; } - if (overlay_address_append(b, my_subscriber)) return WHY("Could not append my sid"); - return 0; } diff --git a/overlay_interface.c b/overlay_interface.c index 8168d02c..e07a3296 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -23,8 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include +#include #include "serval.h" +#include "conf.h" #include "strbuf.h" +#include "strbuf_helpers.h" #include "overlay_buffer.h" #include "overlay_packet.h" #include "str.h" @@ -38,17 +41,6 @@ int overlay_interface_count=0; overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; int overlay_last_interface_number=-1; -struct interface_rules { - char *namespec; - unsigned long long speed_in_bits; - int port; - char type; - char excludeP; - struct interface_rules *next; -}; - -struct interface_rules *interface_filter=NULL; - struct profile_total interface_poll_stats; struct profile_total dummy_poll_stats; @@ -72,7 +64,6 @@ struct profile_total send_packet; static int overlay_tick_interface(int i, time_ms_t now); static void overlay_interface_poll(struct sched_ent *alarm); static void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len); -static long long parse_quantity(char *q); #define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __WHENCE__, (M), (P), (N)) @@ -80,116 +71,6 @@ unsigned char magic_header[]={/* Magic */ 'O',0x10, /* Version */ 0x00,0x01}; -static int overlay_interface_type(char *s) -{ - if (!strcasecmp(s,"ethernet")) return OVERLAY_INTERFACE_ETHERNET; - if (!strcasecmp(s,"wifi")) return OVERLAY_INTERFACE_WIFI; - if (!strcasecmp(s,"other")) return OVERLAY_INTERFACE_UNKNOWN; - if (!strcasecmp(s,"catear")) return OVERLAY_INTERFACE_PACKETRADIO; - return -1; -} - -int overlay_interface_arg(char *arg) -{ - /* Parse an interface argument, of the form: - - <+|->[interfacename][=type] - - +interface tells DNA to sit on that interface - -interface tells DNA to not sit on that interface - +/- without an interface tells DNA to sit on all interfaces. - - The first match rules, so -en0+ tells DNA to use all interfaces, excepting en0 - - The optional =type specifier tells DNA how to handle the interface in terms of - bandwidth:distance relationship for calculating tick times etc. - - The special type =custom allows full specification: - - XXX - Settle the custom specification now that we have changed the interface - management. - */ - - char sign[80]="+"; - char interface_name[80]=""; - char speed[80]="1m"; - char typestring[80]="wifi"; - int port=PORT_DNA; - int type=OVERLAY_INTERFACE_UNKNOWN; - int n=0; - - /* Too long */ - if (strlen(arg)>79) return WHY("interface specification was >79 characters"); - - struct interface_rules *r=calloc(sizeof(struct interface_rules),1); - if (!r) return WHY("calloc(struct interface rules),1) failed"); - - - if (sscanf(arg,"%[+-]%n%[^=:,]%n=%[^:]%n:%d%n:%[^:]%n", - sign,&n,interface_name,&n,typestring,&n,&port,&n,speed,&n)>=1) - { - if (n1) { free(r); return WHY("Sign must be + or -"); } - switch(sign[0]) - { - case '+': break; - case '-': r->excludeP=1; break; - default: - free(r); - return WHY("Invalid interface list item: Must begin with + or -"); - } - - long long speed_in_bits=parse_quantity(speed); - if (speed_in_bits<=1) { - free(r); - return WHY("Interfaces must be capable of at least 1 bit per second"); - } - if (nnamespec=strdup(interface_name); - r->speed_in_bits=speed_in_bits; - r->port=port; - r->type=type; - - r->next=interface_filter; - interface_filter=r; - - return 0; - } - else { free(r); return WHY("Bad interface specification"); } -} - -int overlay_interface_args(const char *arg) -{ - /* Parse series of comma-separated interface definitions from a single argument - */ - int i=0; - char interface[80]; - int len=0; - - for(i=0;arg[i];i++) - { - if (arg[i]==','||arg[i]=='\n') { - interface[len]=0; - if (overlay_interface_arg(interface)) return WHY("Could not add interface"); - len=0; - } else { - if (len<79) { - interface[len++]=arg[i]; - interface[len]=0; - } else - return WHY("Interface definition is too long (each must be <80 characters)"); - } - } - if (len) if (overlay_interface_arg(interface)) return WHY("Could not add final interface"); - return 0; -} - static void overlay_interface_close(overlay_interface *interface){ if (interface->fileP){ @@ -350,7 +231,8 @@ overlay_interface_read_any(struct sched_ent *alarm){ // bind a socket to INADDR_ANY:port // for now, we don't have a graceful close for this interface but it should go away when the process dies -static int overlay_interface_init_any(int port){ +static int overlay_interface_init_any(int port) +{ struct sockaddr_in addr; if (sock_any.poll.fd>0){ @@ -441,9 +323,8 @@ overlay_interface_init_socket(int interface_index) } static int -overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netmask, - struct in_addr broadcast, - int speed_in_bits, int port, int type) +overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr netmask, struct in_addr broadcast, + const struct config_network_interface *ifconfig) { /* Too many interfaces */ if (overlay_interface_count>=OVERLAY_MAX_INTERFACES) return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES"); @@ -456,56 +337,55 @@ overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netma This will ultimately get tuned by the bandwidth and other properties of the interface */ interface->mtu=1200; interface->state=INTERFACE_STATE_DOWN; - interface->bits_per_second=speed_in_bits; - interface->port=port; - interface->type=type; + interface->bits_per_second = ifconfig->speed; + interface->port= ifconfig->port; + interface->type= ifconfig->type; interface->last_tick_ms= -1; // not ticked yet interface->alarm.poll.fd=0; - - // how often do we announce ourselves on this interface? - switch (type) { - case OVERLAY_INTERFACE_PACKETRADIO: - interface->tick_ms = confValueGetInt64Range("mdp.packetradio.tick_ms", 15000LL, 1LL, 3600000LL); - break; - case OVERLAY_INTERFACE_ETHERNET: - interface->tick_ms = confValueGetInt64Range("mdp.ethernet.tick_ms", 500LL, 1LL, 3600000LL); - break; - case OVERLAY_INTERFACE_WIFI: - interface->tick_ms = confValueGetInt64Range("mdp.wifi.tick_ms", 500LL, 1LL, 3600000LL); - break; - case OVERLAY_INTERFACE_UNKNOWN: - interface->tick_ms = confValueGetInt64Range("mdp.unknown.tick_ms", 500LL, 1LL, 3600000LL); - break; - default: - return WHYF("Unsupported interface type %d", type); - } - // allow for a per interface override of tick interval - { - char option_name[64]; - snprintf(option_name, sizeof(option_name), "mdp.%s.tick_ms", (*name=='>'?name+1:name)); - interface->tick_ms = confValueGetInt64Range(option_name, interface->tick_ms, 1LL, 3600000LL); + // How often do we announce ourselves on this interface? + int32_t tick_ms = ifconfig->mdp_tick_ms; + if (tick_ms < 0) { + int i = config_mdp_iftypelist__get(&config.mdp.iftype, &ifconfig->type); + if (i != -1) + tick_ms = config.mdp.iftype.av[i].value.tick_ms; } - - // disable announcements and other broadcasts if tick_ms=0. - if (interface->tick_ms>0) + if (tick_ms < 0) { + switch (ifconfig->type) { + case OVERLAY_INTERFACE_PACKETRADIO: + tick_ms = 15000; + break; + case OVERLAY_INTERFACE_ETHERNET: + tick_ms = 500; + break; + case OVERLAY_INTERFACE_WIFI: + tick_ms = 500; + break; + case OVERLAY_INTERFACE_UNKNOWN: + tick_ms = 500; + break; + default: + return WHYF("Unsupported interface type %d", ifconfig->type); + } + } + assert(tick_ms >= 0); + interface->tick_ms = tick_ms; + + // disable announcements and other broadcasts if tick_ms=0. + if (interface->tick_ms > 0) interface->send_broadcasts=1; else{ interface->send_broadcasts=0; INFOF("Interface %s is running tickless", name); } - if (name[0]=='>') { - interface->fileP=1; + if (ifconfig->dummy[0]) { + interface->fileP = 1; char dummyfile[1024]; - if (name[1]=='/') { - /* Absolute path */ - snprintf(dummyfile, sizeof(dummyfile), "%s", &name[1]); - } else { - const char *interface_folder = confValueGet("interface.folder", serval_instancepath()); - snprintf(dummyfile, sizeof(dummyfile), "%s/%s", interface_folder, &name[1]); - } - + strbuf d = strbuf_local(dummyfile, sizeof dummyfile); + strbuf_path_join(d, serval_instancepath(), config.server.dummy_interface_dir, ifconfig->dummy, NULL); + if (strbuf_overrun(d)) + return WHYF("dummy interface file name overrun: %s", alloca_str_toprint(strbuf_str(d))); if ((interface->alarm.poll.fd = open(dummyfile,O_APPEND|O_RDWR)) < 1) { return WHYF("could not open dummy interface file %s for append", dummyfile); } @@ -781,41 +661,50 @@ overlay_broadcast_ensemble(int interface_number, } } -/* Register the interface, or update the existing interface registration */ +/* Register the real interface, or update the existing interface registration. */ int overlay_interface_register(char *name, struct in_addr addr, - struct in_addr mask) { - struct interface_rules *r, *me; - int i; + struct in_addr mask) +{ struct in_addr broadcast = {.s_addr = addr.s_addr | ~mask.s_addr}; - + if (debug & DEBUG_OVERLAYINTERFACES) { // note, inet_ntop doesn't seem to behave on android DEBUGF("%s address: %s", name, inet_ntoa(addr)); DEBUGF("%s broadcast address: %s", name, inet_ntoa(broadcast)); } - - /* See if the interface is listed in the filter */ - me = NULL; - for (r = interface_filter; r && !me; r = r->next) - if (r->namespec[0] == '\0' || strcasecmp(name, r->namespec) == 0) - me = r; - if (me == NULL || me->excludeP) { + + // Find the matching non-dummy interface rule. + const struct config_network_interface *ifconfig = NULL; + int i; + for (i = 0; i < config.interfaces.ac; ++i, ifconfig = NULL) { + ifconfig = &config.interfaces.av[i].value; + if (!ifconfig->dummy[0]) { + int j; + for (j = 0; j < ifconfig->match.patc; ++j) + if (fnmatch(ifconfig->match.patv[j], name, 0) == 0) + break; + } + } + if (ifconfig == NULL) { if (debug & DEBUG_OVERLAYINTERFACES) - DEBUGF("Interface %s is not interesting.",name); + DEBUGF("Interface %s does not match any rule", name); + return 0; + } + if (ifconfig->exclude) { + if (debug & DEBUG_OVERLAYINTERFACES) + DEBUGF("Interface %s is explicitly excluded", name); return 0; } - int found_interface= -1; - /* Search in the exist list of interfaces */ + int found_interface= -1; for(i = 0; i < overlay_interface_count; i++){ int broadcast_match = 0; int name_match =0; - if (overlay_interfaces[i].broadcast_address.sin_addr.s_addr - == broadcast.s_addr) + if (overlay_interfaces[i].broadcast_address.sin_addr.s_addr == broadcast.s_addr) broadcast_match = 1; name_match = !strcasecmp(overlay_interfaces[i].name, name); @@ -850,7 +739,7 @@ overlay_interface_register(char *name, } /* New interface, so register it */ - if (overlay_interface_init(name, addr, mask, broadcast, me->speed_in_bits, me->port, me->type)) + if (overlay_interface_init(name, addr, mask, broadcast, ifconfig)) return WHYF("Could not initialise newly seen interface %s", name); else if (debug & DEBUG_OVERLAYINTERFACES) DEBUGF("Registered interface %s", name); @@ -858,66 +747,61 @@ overlay_interface_register(char *name, return 0; } -void overlay_interface_discover(struct sched_ent *alarm){ - int i; - struct interface_rules *r; - struct in_addr dummyaddr; - int detect_real_interfaces = 0; - +void overlay_interface_discover(struct sched_ent *alarm) +{ /* Mark all UP interfaces as DETECTING, so we can tell which interfaces are new, and which are dead */ + int i; for (i = 0; i < overlay_interface_count; i++) if (overlay_interfaces[i].state==INTERFACE_STATE_UP) overlay_interfaces[i].state=INTERFACE_STATE_DETECTING; - /* Check through for any virtual dummy interfaces */ - for (r = interface_filter; r != NULL; r = r->next) { - if (r->namespec[0] != '>'){ + /* Register new dummy interfaces */ + int detect_real_interfaces = 0; + const struct config_network_interface *ifconfig = NULL; + for (i = 0; i < config.interfaces.ac; ++i, ifconfig = NULL) { + ifconfig = &config.interfaces.av[i].value; + if (!ifconfig->dummy[0]) { detect_real_interfaces = 1; continue; } - for (i = 0; i < overlay_interface_count; i++) - if (!strcasecmp(overlay_interfaces[i].name,r->namespec)){ + if (strcasecmp(overlay_interfaces[i].name, ifconfig->dummy) == 0) { if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interfaces[i].state=INTERFACE_STATE_UP; break; } - - if (i >= overlay_interface_count){ - /* New interface, so register it */ - overlay_interface_init(r->namespec,dummyaddr,dummyaddr,dummyaddr,1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI); + if (i >= overlay_interface_count) { + // New dummy interface, so register it. + struct in_addr dummyaddr = (struct in_addr){htonl(INADDR_NONE)}; + overlay_interface_init(ifconfig->dummy, dummyaddr, dummyaddr, dummyaddr, ifconfig); } } - /* Look for real interfaces */ - if (detect_real_interfaces){ + // Register new real interfaces + if (detect_real_interfaces) { int no_route = 1; - #ifdef HAVE_IFADDRS_H if (no_route != 0) no_route = doifaddrs(); #endif - #ifdef SIOCGIFCONF if (no_route != 0) no_route = lsif(); #endif - #ifdef linux if (no_route != 0) no_route = scrapeProcNetRoute(); #endif - if (no_route != 0) { FATAL("Unable to get any interface information"); } } - - // detect if any interfaces have gone away and need to be closed + + // Close any interfaces that have gone away. for(i = 0; i < overlay_interface_count; i++) if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interface_close(&overlay_interfaces[i]); - + alarm->alarm = gettime_ms()+5000; alarm->deadline = alarm->alarm + 10000; schedule(alarm); @@ -1284,17 +1168,6 @@ overlay_tick_interface(int i, time_ms_t now) { RETURN(0); } -static long long -parse_quantity(char *q) -{ - if (strlen(q) >= 80) - return WHY("quantity string >=80 characters"); - long long result; - if (str_to_int64_scaled(q, 10, &result, NULL)) - return result; - return WHYF("Illegal quantity: %s", alloca_str_toprint(q)); -} - static void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len) { struct mallocbuf mb = STRUCT_MALLOCBUF_NULL; diff --git a/overlay_olsr.c b/overlay_olsr.c index c0207d10..022e146e 100644 --- a/overlay_olsr.c +++ b/overlay_olsr.c @@ -32,13 +32,12 @@ */ #include "serval.h" +#include "conf.h" #include "overlay_packet.h" #include "overlay_buffer.h" #include "overlay_address.h" #define PACKET_FORMAT_NUMBER 123 -static int local_port =4131; -static int remote_port =4130; static void olsr_read(struct sched_ent *alarm); @@ -60,17 +59,14 @@ int olsr_init_socket(void){ if (read_watch.poll.fd>=0) return 0; - if (!confValueGetBoolean("olsr.enabled",0)) + if (!config.olsr.enable) return 0; - local_port = confValueGetInt64Range("olsr.local.port", local_port, 1LL, 0xFFFFLL); - remote_port = confValueGetInt64Range("olsr.remote.port", remote_port, 1LL, 0xFFFFLL); - - INFOF("Initialising olsr broadcast forwarding via ports %d-%d", local_port, remote_port); + INFOF("Initialising olsr broadcast forwarding via ports %d-%d", config.olsr.local_port, config.olsr.remote_port); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - .sin_port = htons(local_port), + .sin_port = htons(config.olsr.local_port), }; fd = socket(AF_INET,SOCK_DGRAM,0); @@ -208,7 +204,7 @@ static void olsr_read(struct sched_ent *alarm){ return; // drop packets from other port numbers - if (ntohs(addr.sin_port)!=remote_port){ + if (ntohs(addr.sin_port)!= config.olsr.remote_port){ WHYF("Dropping unexpected packet from port %d", ntohs(addr.sin_port)); return; } @@ -232,7 +228,7 @@ static int send_packet(unsigned char *header, int header_len, unsigned char *pay struct sockaddr_in addr={ .sin_family=AF_INET, .sin_addr.s_addr=htonl(INADDR_LOOPBACK), - .sin_port=htons(remote_port), + .sin_port=htons(config.olsr.remote_port), }; struct iovec iov[]={ diff --git a/rhizome.c b/rhizome.c index 04cf7300..0218e292 100644 --- a/rhizome.c +++ b/rhizome.c @@ -18,18 +18,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "conf.h" #include "str.h" #include "rhizome.h" #include int rhizome_enabled() { - return confValueGetBoolean("rhizome.enable", 1);; + return config.rhizome.enable; } int rhizome_fetch_delay_ms() { - return confValueGetInt64Range("rhizome.fetch_delay_ms", 50, 1, 3600000); + return config.rhizome.fetch_delay_ms; } /* Import a bundle from a pair of files, one containing the manifest and the optional other diff --git a/rhizome.h b/rhizome.h index ab421cbf..a12e5290 100644 --- a/rhizome.h +++ b/rhizome.h @@ -17,8 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifndef __SERVALDNA__RHIZOME_H +#define __SERVALDNA__RHIZOME_H + #include #include "sha2.h" +#include "str.h" #include "strbuf.h" #include "nacl.h" #include @@ -45,6 +49,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define RHIZOME_HTTP_PORT 4110 #define RHIZOME_HTTP_PORT_MAX 4150 +typedef struct rhizome_bk_binary { + unsigned char binary[RHIZOME_BUNDLE_KEY_BYTES]; +} rhizome_bk_t; + +#define RHIZOME_BK_NONE ((rhizome_bk_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}) + +__RHIZOME_INLINE int rhizome_is_bk_none(const rhizome_bk_t *bk) { + return is_all_matching(bk->binary, sizeof bk->binary, 0); +} + extern time_ms_t rhizome_voice_timeout; #define RHIZOME_PRIORITY_HIGHEST RHIZOME_PRIORITY_SERVAL_CORE @@ -564,3 +578,5 @@ struct http_response_parts { }; int unpack_http_response(char *response, struct http_response_parts *parts); + +#endif //__SERVALDNA__RHIZOME_H diff --git a/rhizome_database.c b/rhizome_database.c index 333e367d..690fa9f9 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -21,32 +21,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include "serval.h" +#include "conf.h" #include "rhizome.h" #include "strbuf.h" +#include "strbuf_helpers.h" #include "str.h" -long long rhizome_space=0; -static const char *rhizome_thisdatastore_path = NULL; +static char rhizome_thisdatastore_path[256]; const char *rhizome_datastore_path() { - if (!rhizome_thisdatastore_path) + if (!rhizome_thisdatastore_path[0]) rhizome_set_datastore_path(NULL); return rhizome_thisdatastore_path; } int rhizome_set_datastore_path(const char *path) { - if (!path) - path = confValueGet("rhizome.datastore_path", NULL); - if (path) { - rhizome_thisdatastore_path = strdup(path); - if (path[0] != '/') - WARNF("Dangerous rhizome.datastore_path setting: '%s' -- should be absolute", rhizome_thisdatastore_path); - } else { - rhizome_thisdatastore_path = serval_instancepath(); - WARNF("Rhizome datastore path not configured -- using instance path '%s'", rhizome_thisdatastore_path); - } + strbuf b = strbuf_local(rhizome_thisdatastore_path, sizeof rhizome_thisdatastore_path); + strbuf_path_join(b, serval_instancepath(), config.rhizome.datastore_path, path, NULL); + INFOF("Rhizome datastore path = %s", alloca_str_toprint(rhizome_thisdatastore_path)); return 0; } @@ -197,11 +191,8 @@ int rhizome_opendb() int loglevel = (debug & DEBUG_RHIZOME) ? LOG_LEVEL_DEBUG : LOG_LEVEL_SILENT; /* Read Rhizome configuration */ - double rhizome_kb = atof(confValueGet("rhizome_kb", "1024")); - rhizome_space = 1024LL * rhizome_kb; if (debug&DEBUG_RHIZOME) { - DEBUGF("serval.conf:rhizome_kb=%.f", rhizome_kb); - DEBUGF("Rhizome will use %lldB of storage for its database.", rhizome_space); + DEBUGF("Rhizome will use %lluB of storage for its database.", (unsigned long long) config.rhizome.database_size); } /* Create tables as required */ sqlite_exec_void_loglevel(loglevel, "PRAGMA auto_vacuum=2;"); @@ -581,7 +572,7 @@ long long rhizome_database_used_bytes() int rhizome_make_space(int group_priority, long long bytes) { /* Asked for impossibly large amount */ - if (bytes>=(rhizome_space-65536)) + if (bytes>=(config.rhizome.database_size-65536)) return WHYF("bytes=%lld is too large", bytes); long long db_used = rhizome_database_used_bytes(); @@ -589,7 +580,7 @@ int rhizome_make_space(int group_priority, long long bytes) return -1; /* If there is already enough space now, then do nothing more */ - if (db_used<=(rhizome_space-bytes-65536)) + if (db_used<=(config.rhizome.database_size-bytes-65536)) return 0; /* Okay, not enough space, so free up some. */ @@ -597,7 +588,7 @@ int rhizome_make_space(int group_priority, long long bytes) sqlite3_stmt *statement = sqlite_prepare(&retry, "select id,length from files where highestpriority < %d order by descending length", group_priority); if (!statement) return -1; - while (bytes > (rhizome_space - 65536 - rhizome_database_used_bytes()) + while (bytes > (config.rhizome.database_size - 65536 - rhizome_database_used_bytes()) && sqlite_step_retry(&retry, statement) == SQLITE_ROW ) { /* Make sure we can drop this blob, and if so drop it, and recalculate number of bytes required */ diff --git a/rhizome_direct.c b/rhizome_direct.c index 60eaa2f1..34f72bb6 100644 --- a/rhizome_direct.c +++ b/rhizome_direct.c @@ -108,6 +108,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "conf.h" #include "rhizome.h" #include "str.h" #include @@ -480,6 +481,38 @@ rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int pref } +static int rhizome_sync_with_peers(int mode, int peer_count, const struct config_rhizome_peer *const *peers) +{ + + /* Get iterator capable of 64KB buffering. + In future we should parse the sync URL and base the buffer size on the + transport and allowable traffic volumes. */ + rhizome_direct_transport_state_http *state = emalloc_zero(sizeof(rhizome_direct_transport_state_http)); + /* XXX This code runs each sync in series, when we can probably do them in + parallel. But we can't really do them in parallel until we make the + synchronisation process fully asynchronous, which probably won't happen + for a while yet. + Also, we don't currently parse the URI protocol field fully. */ + int peer_number; + for (peer_number = 0; peer_number < peer_count; ++peer_number) { + const struct config_rhizome_peer *peer = peers[peer_number]; + if (strcasecmp(peer->protocol, "http") != 0) + return WHYF("Unsupported Rhizome Direct protocol %s", alloca_str_toprint(peer->protocol)); + strbuf h = strbuf_local(state->host, sizeof state->host); + strbuf_puts(h, peer->host); + if (strbuf_overrun(h)) + return WHYF("Rhizome Direct host name too long: %s", alloca_str_toprint(peer->host)); + state->port = peer->port; + DEBUGF("Rhizome direct peer is %s://%s:%d", peer->protocol, state->host, state->port); + rhizome_direct_sync_request *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, 65536, 0, mode, state); + rhizome_direct_start_sync_request(s); + if (rd_sync_handle_count > 0) + while (fd_poll() && rd_sync_handle_count > 0) + ; + } + return 0; +} + int app_rhizome_direct_sync(int argc, const char *const *argv, struct command_line_option *o, void *context) { /* Attempt to connect with a remote Rhizome Direct instance, @@ -488,83 +521,30 @@ int app_rhizome_direct_sync(int argc, const char *const *argv, struct command_li int mode=3; /* two-way sync */ if (!strcasecmp(modeName,"push")) mode=1; /* push only */ if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */ - DEBUGF("sync direction = %d",mode); - - /* Get iterator capable of 64KB buffering. - In future we should parse the sync URL and base the buffer size on the - transport and allowable traffic volumes. */ - rhizome_direct_transport_state_http - *state=calloc(sizeof(rhizome_direct_transport_state_http),1); - const char *sync_url=NULL; - int peer_count=confValueGetInt64("rhizome.direct.peer.count",0); - int peer_number=0; - char peer_var[128]; - if (argv[3]) { - peer_count=1; - sync_url=argv[3]; - } - - if (peer_count<1) { - DEBUG("No rhizome direct peers were configured or supplied."); - } - - /* XXX This code runs each sync in series, when we can probably do them in - parallel. But we can't really do them in parallel until we make the - synchronisation process fully asynchronous, which probably won't happen - for a while yet. - Also, we don't currently parse the URI protocol field fully. */ - next_peer: - if (!sync_url) { - snprintf(peer_var,128,"rhizome.direct.peer.%d",peer_number); - sync_url=confValueGet(peer_var, NULL); - } - - if (strlen(sync_url)>1020) - { - DEBUG("rhizome direct URI too long"); - return -1; + struct config_rhizome_peer peer; + const struct config_rhizome_peer *peers[1] = { &peer }; + int result = cf_opt_rhizome_peer_from_uri(&peer, argv[3]); + if (result == CFOK) + return rhizome_sync_with_peers(mode, 1, peers); + else { + strbuf b = strbuf_alloca(128); + strbuf_cf_flag_reason(b, result); + return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(argv[3]), strbuf_str(b)); } - - char protocol[1024]; - state->port=RHIZOME_HTTP_PORT; - int ok=0; - if (sscanf(sync_url,"%[^:]://%[^:]:%d",protocol,state->host,&state->port)>=2) - ok=1; - if (!ok) sprintf(protocol,"http"); - if ((!ok)&&(sscanf(sync_url,"%[^:]:%d",state->host,&state->port)>=1)) - ok=2; - if (!ok) - { - DEBUG("could not parse rhizome direct URI"); - return -1; - } - DEBUGF("Rhizome direct peer is %s://%s:%d (parse route %d)", - protocol,state->host,state->port,ok); - - if (strcasecmp(protocol,"http")) { - DEBUG("Unsupport Rhizome Direct synchronisation protocol." - " Only HTTP is supported at present."); + } else if (config.rhizome.direct.peer.ac == 0) { + DEBUG("No rhizome direct peers were configured or supplied"); return -1; + } else { + const struct config_rhizome_peer *peers[config.rhizome.direct.peer.ac]; + int i; + for (i = 0; i < config.rhizome.direct.peer.ac; ++i) + peers[i] = &config.rhizome.direct.peer.av[i].value; + return rhizome_sync_with_peers(mode, config.rhizome.direct.peer.ac, peers); } - - rhizome_direct_sync_request - *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, - 65536,0,mode,state); - - rhizome_direct_start_sync_request(s); - - if (rd_sync_handle_count>0) - while(fd_poll()&&(rd_sync_handle_count>0)) continue; - - sync_url=NULL; - peer_number++; - if (peer_numberpath,"/rhizome/import")) { switch(r->fields_seen) { @@ -175,17 +174,16 @@ int rhizome_direct_form_received(rhizome_http_request *r) why we leave it disabled by default, but it will be sufficient for testing possible uses, including integration with OpenDataKit. */ - else if (submitBareFileURI&&(!strcmp(r->path,submitBareFileURI))) { - if (strcmp(inet_ntoa(r->requestor.sin_addr), - confValueGet("rhizome.api.addfile.allowedaddress","127.0.0.1"))) - { - DEBUGF("rhizome.api.addfile request received from %s, but is only allowed from %s", - inet_ntoa(r->requestor.sin_addr), - confValueGet("rhizome.api.addfile.allowedaddress", "127.0.0.1")); + else if (config.rhizome.api.addfile.uri_path[0] && strcmp(r->path, config.rhizome.api.addfile.uri_path) == 0) { + if (r->requestor.sin_addr.s_addr != config.rhizome.api.addfile.allow_host.s_addr) { + DEBUGF("rhizome.api.addfile request received from %s, but is only allowed from %s", + inet_ntoa(r->requestor.sin_addr), + inet_ntoa(config.rhizome.api.addfile.allow_host) + ); - rhizome_direct_clear_temporary_files(r); - return rhizome_server_simple_http_response(r,404,"Not available from here."); - } + rhizome_direct_clear_temporary_files(r); + return rhizome_server_simple_http_response(r,404,"Not available from here."); + } switch(r->fields_seen) { case RD_MIME_STATE_DATAHEADERS: @@ -201,14 +199,13 @@ int rhizome_direct_form_received(rhizome_http_request *r) char filepath[1024]; snprintf(filepath,1024,"rhizomedirect.%d.data",r->alarm.poll.fd); - const char *manifestTemplate - =confValueGet("rhizome.api.addfile.manifesttemplate", NULL); - - if (manifestTemplate&&access(manifestTemplate, R_OK) != 0) - { - rhizome_direct_clear_temporary_files(r); - return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.manifesttemplate points to a file I could not read."); - } + char manifestTemplate[1024]; + strbuf b = strbuf_local(manifestTemplate, sizeof manifestTemplate); + strbuf_path_join(b, serval_instancepath(), config.rhizome.api.addfile.manifest_template_file, NULL); + if (manifestTemplate[0] && access(manifestTemplate, R_OK) != 0) { + rhizome_direct_clear_temporary_files(r); + return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.manifesttemplate points to a file I could not read."); + } rhizome_manifest *m = rhizome_new_manifest(); if (!m) @@ -218,7 +215,7 @@ int rhizome_direct_form_received(rhizome_http_request *r) return WHY("Manifest struct could not be allocated -- not added to rhizome"); } - if (manifestTemplate) + if (manifestTemplate[0]) if (rhizome_read_manifest_file(m, manifestTemplate, 0) == -1) { rhizome_manifest_free(m); rhizome_direct_clear_temporary_files(r); @@ -252,11 +249,10 @@ int rhizome_direct_form_received(rhizome_http_request *r) } const char *senderhex = rhizome_manifest_get(m, "sender", NULL, 0); - if (!senderhex) - senderhex = confValueGet("rhizome.api.addfile.author", NULL); if (senderhex) fromhexstr(m->author, senderhex, SID_SIZE); - const char *bskhex = confValueGet("rhizome.api.addfile.bundlesecretkey", NULL); + else if (!is_sid_any(config.rhizome.api.addfile.default_author.binary)) + memcpy(m->author, config.rhizome.api.addfile.default_author.binary, sizeof m->author); // TODO replace with sid_t struct assignment /* Bind an ID to the manifest, and also bind the file. Then finalise the manifest. But if the manifest already contains an ID, don't override it. */ @@ -266,13 +262,11 @@ int rhizome_direct_form_received(rhizome_http_request *r) m = NULL; rhizome_direct_clear_temporary_files(r); return rhizome_server_simple_http_response(r,500,"Could not bind manifest to an ID"); - } - } else if (bskhex) { + } + } else if (!rhizome_is_bk_none(&config.rhizome.api.addfile.bundle_secret_key)) { /* Allow user to specify a bundle secret key so that the same bundle can be updated, rather than creating a new bundle each time. */ - unsigned char bsk[RHIZOME_BUNDLE_KEY_BYTES]; - fromhexstr(bsk,bskhex,RHIZOME_BUNDLE_KEY_BYTES); - memcpy(m->cryptoSignSecret, bsk, RHIZOME_BUNDLE_KEY_BYTES); + memcpy(m->cryptoSignSecret, config.rhizome.api.addfile.bundle_secret_key.binary, RHIZOME_BUNDLE_KEY_BYTES); if (rhizome_verify_bundle_privatekey(m,m->cryptoSignSecret,m->cryptoSignPublic) == -1) { rhizome_manifest_free(m); m = NULL; @@ -295,7 +289,7 @@ int rhizome_direct_form_received(rhizome_http_request *r) rhizome_manifest_free(m); rhizome_direct_clear_temporary_files(r); return rhizome_server_simple_http_response(r,500,"Could not bind manifest to file"); - } + } if (rhizome_manifest_finalise(m)) { rhizome_manifest_free(m); rhizome_direct_clear_temporary_files(r); @@ -576,8 +570,7 @@ struct http_request_parts { int rhizome_direct_parse_http_request(rhizome_http_request *r) { - const char *submitBareFileURI=confValueGet("rhizome.api.addfile.uri", NULL); - DEBUGF("uri=%s", submitBareFileURI ? alloca_str_toprint(submitBareFileURI) : "NULL"); + DEBUGF("uri=%s", alloca_str_toprint(config.rhizome.api.addfile.uri_path)); /* Switching to writing, so update the call-back */ r->alarm.poll.events=POLLOUT; @@ -630,7 +623,7 @@ int rhizome_direct_parse_http_request(rhizome_http_request *r) } else if (strcmp(verb, "POST") == 0 && ( strcmp(path, "/rhizome/import") == 0 || strcmp(path, "/rhizome/enquiry") == 0 - || (submitBareFileURI && strcmp(path, submitBareFileURI) == 0) + || (config.rhizome.api.addfile.uri_path[0] && strcmp(path, config.rhizome.api.addfile.uri_path) == 0) ) ) { const char *cl_str=str_str(headers,"Content-Length: ",headerlen); diff --git a/serval.h b/serval.h index 974d7091..658780dc 100644 --- a/serval.h +++ b/serval.h @@ -114,7 +114,6 @@ struct in_addr { #include "xprintf.h" #include "log.h" #include "net.h" -#include "conf.h" #include "os.h" /* UDP Port numbers for various Serval services. @@ -141,7 +140,22 @@ struct in_addr { /* Limit packet payloads to minimise packet loss of big packets in mesh networks */ #define MAX_DATA_BYTES 256 -double simulatedBER; +#ifdef ANDROID +#define DEFAULT_INSTANCE_PATH "/data/data/org.servalproject/var/serval-node" +#else +#define DEFAULT_INSTANCE_PATH "/var/serval-node" +#endif + +/* Handy statement for forming a path to an instance file in a char buffer whose declaration + * is in scope (so that sizeof(buf) will work). Evaluates to true if the pathname fitted into + * the provided buffer, false (0) otherwise (after logging an error). + */ +#define FORM_SERVAL_INSTANCE_PATH(buf, path) (form_serval_instance_path(buf, sizeof(buf), (path))) + +const char *serval_instancepath(); +int create_serval_instance_dir(); +int form_serval_instance_path(char *buf, size_t bufsiz, const char *path); +void serval_setinstancepath(const char *instancepath); extern int serverMode; extern int servalShutdown; @@ -316,7 +330,7 @@ typedef struct overlay_interface { struct sched_ent alarm; char name[256]; int recv_offset; - int fileP; + int fileP; // dummyP int bits_per_second; int port; int type; @@ -331,7 +345,7 @@ typedef struct overlay_interface { For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms. These figures will be refined over time, and we will allow people to set them per-interface. */ - int tick_ms; /* milliseconds per tick */ + unsigned tick_ms; /* milliseconds per tick */ int send_broadcasts; /* The time of the last tick on this interface in milli seconds */ time_ms_t last_tick_ms; @@ -400,7 +414,12 @@ typedef struct overlay_txqueue { extern overlay_txqueue overlay_tx[OQ_MAX]; -ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct sockaddr *recvaddr, socklen_t *recvaddrlen); +typedef struct sid_binary { + unsigned char binary[SID_SIZE]; +} sid_t; + +#define SID_ANY ((sid_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}) +#define SID_BROADCAST ((sid_t){{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}) // is the SID entirely 0xFF? #define is_sid_broadcast(SID) is_all_matching(SID, SID_SIZE, 0xFF) @@ -443,7 +462,6 @@ time_ms_t overlay_time_until_next_tick(); int overlay_add_selfannouncement(); int overlay_frame_append_payload(overlay_interface *interface, struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b); -int overlay_interface_args(const char *arg); int overlay_rhizome_add_advertisements(int interface_number,struct overlay_buffer *e); int overlay_add_local_identity(unsigned char *s); void overlay_update_queue_schedule(overlay_txqueue *queue, struct overlay_frame *frame); @@ -511,9 +529,6 @@ int rhizome_opendb(); int parseCommandLine(const char *argv0, int argc, const char *const *argv); -int form_serval_instance_path(char * buf, size_t bufsiz, const char *path); -int create_serval_instance_dir(); - int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax); int overlay_mdp_reply_error(int sock, struct sockaddr_un *recvaddr,int recvaddrlen, @@ -614,8 +629,6 @@ int cli_puts(const char *str); int cli_printf(const char *fmt, ...); int cli_delim(const char *opt); -int is_configvarname(const char *arg); - int overlay_mdp_getmyaddr(int index,unsigned char *sid); int overlay_mdp_bind(unsigned char *localaddr,int port); int overlay_route_node_info(overlay_mdp_nodeinfo *node_info); diff --git a/server.c b/server.c index 086e6ec5..57c1b5cd 100644 --- a/server.c +++ b/server.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" +#include "conf.h" #include "strbuf.h" #include "strbuf_helpers.h" @@ -36,7 +37,6 @@ char *exec_args[EXEC_NARGS + 1]; int exec_argc = 0; int serverMode=0; -int serverRespawnOnCrash = 0; int servalShutdown = 0; static int server_getpid = 0; @@ -95,7 +95,6 @@ int server(char *backing_file) sleep_ms(atoi(delay)); serverMode = 1; - serverRespawnOnCrash = confValueGetBoolean("server.respawn_on_crash", 0); /* Catch crash signals so that we can log a backtrace before expiring. */ struct sigaction sig; @@ -362,7 +361,7 @@ void crash_handler(int signal) WHYF("Caught %s", buf); dump_stack(); BACKTRACE; - if (serverRespawnOnCrash) { + if (config.server.respawn_on_crash) { int i; for(i=0;i-1) diff --git a/sourcefiles.mk b/sourcefiles.mk index 36fb73be..95c9a3aa 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -4,6 +4,9 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \ $(SERVAL_BASE)codecs.c \ $(SERVAL_BASE)commandline.c \ $(SERVAL_BASE)conf.c \ + $(SERVAL_BASE)conf_om.c \ + $(SERVAL_BASE)conf_parse.c \ + $(SERVAL_BASE)conf_schema.c \ $(SERVAL_BASE)crypto.c \ $(SERVAL_BASE)dataformats.c \ $(SERVAL_BASE)directory_client.c \ @@ -18,6 +21,7 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \ $(SERVAL_BASE)mdp_client.c \ $(SERVAL_BASE)os.c \ $(SERVAL_BASE)mem.c \ + $(SERVAL_BASE)instance.c \ $(SERVAL_BASE)monitor.c \ $(SERVAL_BASE)monitor-client.c \ $(SERVAL_BASE)monitor-cli.c \