mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-21 01:42:18 +00:00
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:
parent
d3c2205d44
commit
caa209fc1d
@ -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 \
|
||||
|
@ -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
624
conf.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
Serval Distributed Numbering Architecture (DNA)
|
||||
Copyright (C) 2010-2012 Paul Gardner-Stephen
|
||||
Serval DNA configuration
|
||||
Copyright (C) 2012 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@ -23,208 +23,108 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "str.h"
|
||||
|
||||
/* This predicate function defines the constraints on configuration option names.
|
||||
Valid:
|
||||
foo
|
||||
foo.bar
|
||||
foo.bar.chow
|
||||
_word
|
||||
word1
|
||||
word_1
|
||||
Invalid:
|
||||
foo.
|
||||
.foo
|
||||
1foo
|
||||
foo.bar.
|
||||
12
|
||||
1.2.3
|
||||
foo bar
|
||||
@author Andrew Bettison <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
572
conf.h
@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) 2010-2012 Paul Gardner-Stephen, Serval Project.
|
||||
Serval DNA configuration
|
||||
Copyright (C) 2012 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@ -16,42 +17,539 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <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
137
conf_om.c
@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "str.h"
|
||||
#include "strbuf.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "conf.h"
|
||||
|
||||
static const char *cf_find_keyend(const char *const key, const char *const fullkeyend)
|
||||
{
|
||||
@ -44,6 +44,34 @@ static const char *cf_find_keyend(const char *const key, const char *const fullk
|
||||
return s;
|
||||
}
|
||||
|
||||
/* This predicate function defines the constraints on configuration option names.
|
||||
* Valid:
|
||||
* foo
|
||||
* foo.bar
|
||||
* foo.bar.chow
|
||||
* _word
|
||||
* word1
|
||||
* word_1
|
||||
* Invalid:
|
||||
* foo.
|
||||
* .foo
|
||||
* 1foo
|
||||
* foo.bar.
|
||||
* 12
|
||||
* 1.2.3
|
||||
* foo bar
|
||||
* @author Andrew Bettison <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
60
conf_parse.c
60
conf_parse.c
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
498
config.h
@ -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
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
33
dna_helper.c
33
dna_helper.c
@ -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;
|
||||
|
@ -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
57
instance.c
Normal 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
30
log.c
@ -46,8 +46,6 @@ const struct __sourceloc __whence = __NOWHERE__;
|
||||
debugflags_t debug = 0;
|
||||
|
||||
static FILE *logfile = NULL;
|
||||
static int flag_show_pid = -1;
|
||||
static int flag_show_time = -1;
|
||||
|
||||
/* The logbuf is used to accumulate log messages before the log file is open and ready for
|
||||
writing.
|
||||
@ -78,11 +76,11 @@ static FILE *_open_logging()
|
||||
if (!logfile) {
|
||||
const char *logpath = getenv("SERVALD_LOG_FILE");
|
||||
if (!logpath) {
|
||||
if (confBusy())
|
||||
if (cf_limbo)
|
||||
return NULL;
|
||||
logpath = confValueGet("log.file", NULL);
|
||||
logpath = config.log.file;
|
||||
}
|
||||
if (!logpath) {
|
||||
if (!logpath || !logpath[0]) {
|
||||
logfile = stderr; //fopen("/tmp/foo", "a");
|
||||
INFO("No logfile configured -- logging to stderr");
|
||||
} else if ((logfile = fopen(logpath, "a"))) {
|
||||
@ -102,20 +100,6 @@ FILE *open_logging()
|
||||
return _open_logging();
|
||||
}
|
||||
|
||||
static int show_pid()
|
||||
{
|
||||
if (flag_show_pid < 0 && !confBusy())
|
||||
flag_show_pid = confValueGetBoolean("log.show_pid", 0);
|
||||
return flag_show_pid;
|
||||
}
|
||||
|
||||
static int show_time()
|
||||
{
|
||||
if (flag_show_time < 0 && !confBusy())
|
||||
flag_show_time = confValueGetBoolean("log.show_time", 0);
|
||||
return flag_show_time;
|
||||
}
|
||||
|
||||
void close_logging()
|
||||
{
|
||||
if (logfile) {
|
||||
@ -144,10 +128,8 @@ static int _log_prepare(int level, struct __sourceloc whence)
|
||||
return 0;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
int showtime = show_time();
|
||||
if (showtime)
|
||||
if (config.log.show_time)
|
||||
gettimeofday(&tv, NULL);
|
||||
int showpid = show_pid();
|
||||
_open_logging(); // Put initial INFO message at start of log file
|
||||
// No calls outside log.c from this point on.
|
||||
if (strbuf_is_empty(&logbuf))
|
||||
@ -165,9 +147,9 @@ static int _log_prepare(int level, struct __sourceloc whence)
|
||||
}
|
||||
strbuf_sprintf(&logbuf, "%-6.6s ", levelstr);
|
||||
#endif
|
||||
if (showpid)
|
||||
if (config.log.show_pid)
|
||||
strbuf_sprintf(&logbuf, "[%5u] ", getpid());
|
||||
if (showtime) {
|
||||
if (config.log.show_time) {
|
||||
if (tv.tv_sec == 0) {
|
||||
strbuf_puts(&logbuf, "NOTIME______ ");
|
||||
} else {
|
||||
|
2
main.c
2
main.c
@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -31,6 +32,7 @@ int main(int argc, char **argv)
|
||||
|
||||
srandomdev();
|
||||
server_save_argv(argc, (const char*const*)argv);
|
||||
cf_init();
|
||||
int status = parseCommandLine(argv[0], argc - 1, (const char*const*)&argv[1]);
|
||||
#if defined WIN32
|
||||
WSACleanup();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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[]={
|
||||
|
@ -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
|
||||
|
16
rhizome.h
16
rhizome.h
@ -17,8 +17,12 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SERVALDNA__RHIZOME_H
|
||||
#define __SERVALDNA__RHIZOME_H
|
||||
|
||||
#include <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
|
||||
|
@ -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 */
|
||||
|
122
rhizome_direct.c
122
rhizome_direct.c
@ -108,6 +108,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "rhizome.h"
|
||||
#include "str.h"
|
||||
#include <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);
|
||||
|
@ -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);
|
||||
|
35
serval.h
35
serval.h
@ -114,7 +114,6 @@ struct in_addr {
|
||||
#include "xprintf.h"
|
||||
#include "log.h"
|
||||
#include "net.h"
|
||||
#include "conf.h"
|
||||
#include "os.h"
|
||||
|
||||
/* UDP Port numbers for various Serval services.
|
||||
@ -141,7 +140,22 @@ struct in_addr {
|
||||
/* Limit packet payloads to minimise packet loss of big packets in mesh networks */
|
||||
#define MAX_DATA_BYTES 256
|
||||
|
||||
double simulatedBER;
|
||||
#ifdef ANDROID
|
||||
#define DEFAULT_INSTANCE_PATH "/data/data/org.servalproject/var/serval-node"
|
||||
#else
|
||||
#define DEFAULT_INSTANCE_PATH "/var/serval-node"
|
||||
#endif
|
||||
|
||||
/* Handy statement for forming a path to an instance file in a char buffer whose declaration
|
||||
* is in scope (so that sizeof(buf) will work). Evaluates to true if the pathname fitted into
|
||||
* the provided buffer, false (0) otherwise (after logging an error).
|
||||
*/
|
||||
#define FORM_SERVAL_INSTANCE_PATH(buf, path) (form_serval_instance_path(buf, sizeof(buf), (path)))
|
||||
|
||||
const char *serval_instancepath();
|
||||
int create_serval_instance_dir();
|
||||
int form_serval_instance_path(char *buf, size_t bufsiz, const char *path);
|
||||
void serval_setinstancepath(const char *instancepath);
|
||||
|
||||
extern int serverMode;
|
||||
extern int servalShutdown;
|
||||
@ -316,7 +330,7 @@ typedef struct overlay_interface {
|
||||
struct sched_ent alarm;
|
||||
char name[256];
|
||||
int recv_offset;
|
||||
int fileP;
|
||||
int fileP; // dummyP
|
||||
int bits_per_second;
|
||||
int port;
|
||||
int type;
|
||||
@ -331,7 +345,7 @@ typedef struct overlay_interface {
|
||||
For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms.
|
||||
These figures will be refined over time, and we will allow people to set them per-interface.
|
||||
*/
|
||||
int tick_ms; /* milliseconds per tick */
|
||||
unsigned tick_ms; /* milliseconds per tick */
|
||||
int send_broadcasts;
|
||||
/* The time of the last tick on this interface in milli seconds */
|
||||
time_ms_t last_tick_ms;
|
||||
@ -400,7 +414,12 @@ typedef struct overlay_txqueue {
|
||||
|
||||
extern overlay_txqueue overlay_tx[OQ_MAX];
|
||||
|
||||
ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct sockaddr *recvaddr, socklen_t *recvaddrlen);
|
||||
typedef struct sid_binary {
|
||||
unsigned char binary[SID_SIZE];
|
||||
} sid_t;
|
||||
|
||||
#define SID_ANY ((sid_t){{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}})
|
||||
#define SID_BROADCAST ((sid_t){{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}})
|
||||
|
||||
// is the SID entirely 0xFF?
|
||||
#define is_sid_broadcast(SID) is_all_matching(SID, SID_SIZE, 0xFF)
|
||||
@ -443,7 +462,6 @@ time_ms_t overlay_time_until_next_tick();
|
||||
|
||||
int overlay_add_selfannouncement();
|
||||
int overlay_frame_append_payload(overlay_interface *interface, struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b);
|
||||
int overlay_interface_args(const char *arg);
|
||||
int overlay_rhizome_add_advertisements(int interface_number,struct overlay_buffer *e);
|
||||
int overlay_add_local_identity(unsigned char *s);
|
||||
void overlay_update_queue_schedule(overlay_txqueue *queue, struct overlay_frame *frame);
|
||||
@ -511,9 +529,6 @@ int rhizome_opendb();
|
||||
|
||||
int parseCommandLine(const char *argv0, int argc, const char *const *argv);
|
||||
|
||||
int form_serval_instance_path(char * buf, size_t bufsiz, const char *path);
|
||||
int create_serval_instance_dir();
|
||||
|
||||
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||
int overlay_mdp_reply_error(int sock,
|
||||
struct sockaddr_un *recvaddr,int recvaddrlen,
|
||||
@ -614,8 +629,6 @@ int cli_puts(const char *str);
|
||||
int cli_printf(const char *fmt, ...);
|
||||
int cli_delim(const char *opt);
|
||||
|
||||
int is_configvarname(const char *arg);
|
||||
|
||||
int overlay_mdp_getmyaddr(int index,unsigned char *sid);
|
||||
int overlay_mdp_bind(unsigned char *localaddr,int port);
|
||||
int overlay_route_node_info(overlay_mdp_nodeinfo *node_info);
|
||||
|
5
server.c
5
server.c
@ -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)
|
||||
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user