Integrate new config into servald

Not passing any tests yet, but compiles and links and simple uses do not
SEGV.
This commit is contained in:
Andrew Bettison 2012-12-04 14:12:28 +10:30
parent d3c2205d44
commit caa209fc1d
29 changed files with 1268 additions and 1533 deletions

View File

@ -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 \

View File

@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <jni.h>
#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();
// </kludge>
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;
// <kludge> See app_config_set()
confReloadIfChanged();
struct cf_om_node *root = cf_om_reload();
// </kludge>
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;

624
conf.c
View File

@ -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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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();
}

572
conf.h
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#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 <andrew@servalproject.com>
*/
#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 <stdint.h>
#include <arpa/inet.h>
#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

137
conf_om.c
View File

@ -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 <andrew@servalproject.com>
*/
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;
}
}
}

View File

@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <assert.h>
#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

View File

@ -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);

View File

@ -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,)

498
config.h
View File

@ -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 <andrew@servalproject.com>
*/
#include <stdint.h>
#include <arpa/inet.h>
#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

View File

@ -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

View File

@ -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));
}

View File

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/stat.h>
#include <signal.h>
#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;

View File

@ -12,6 +12,7 @@ HDRS= fifo.h \
strbuf_helpers.h \
sha2.h \
conf.h \
conf_schema.h \
crypto.h \
log.h \
net.h \

57
instance.c Normal file
View File

@ -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 <stdlib.h>
#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);
}

30
log.c
View File

@ -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 {

2
main.c
View File

@ -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();

View File

@ -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

View File

@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/stat.h>
#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;

View File

@ -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;
}

View File

@ -23,8 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <arpa/inet.h>
#include <assert.h>
#include <time.h>
#include <fnmatch.h>
#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 (n<strlen(arg)) { free(r); return WHY("Extra junk at end of interface specification"); }
if (strlen(sign)>1) { 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 (n<strlen(arg)) return WHY("Extra stuff at end of interface specification");
type=overlay_interface_type(typestring);
if (type<0) { free(r); return WHY("Invalid interface type in specification"); }
/* Okay, register the interface preference */
r->namespec=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;

View File

@ -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[]={

View File

@ -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 <stdlib.h>
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

View File

@ -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 <sqlite3.h>
#include "sha2.h"
#include "str.h"
#include "strbuf.h"
#include "nacl.h"
#include <sys/stat.h>
@ -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

View File

@ -21,32 +21,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <stdlib.h>
#include <time.h>
#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 */

View File

@ -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 <assert.h>
@ -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_number<peer_count) goto next_peer;
return 0;
}
rhizome_direct_bundle_cursor *rhizome_direct_bundle_iterator(int buffer_size)
{
rhizome_direct_bundle_cursor *r=calloc(sizeof(rhizome_direct_bundle_cursor),1);

View File

@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "rhizome.h"
#include "conf.h"
#include "str.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
@ -43,8 +44,6 @@ int rhizome_direct_clear_temporary_files(rhizome_http_request *r)
int rhizome_direct_form_received(rhizome_http_request *r)
{
const char *submitBareFileURI=confValueGet("rhizome.api.addfile.uri", NULL);
/* Process completed form based on the set of fields seen */
if (!strcmp(r->path,"/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);

View File

@ -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);

View File

@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/stat.h>
#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<overlay_interface_count;i++)
if (overlay_interfaces[i].alarm.poll.fd>-1)

View File

@ -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 \