mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Server daemon reloads config every 1 sec
This commit is contained in:
parent
fe3e7da5c6
commit
8d5862d599
@ -627,9 +627,6 @@ int app_server_start(int argc, const char *const *argv, const struct command_lin
|
||||
streams, and start a new process session so that if we are being started by an adb
|
||||
shell session, then we don't receive a SIGHUP when the adb shell process ends. */
|
||||
close_logging();
|
||||
|
||||
//TODO close config
|
||||
|
||||
int fd;
|
||||
if ((fd = open("/dev/null", O_RDWR, 0)) == -1)
|
||||
_exit(WHY_perror("open"));
|
||||
|
162
conf.c
162
conf.c
@ -32,12 +32,14 @@ struct file_meta {
|
||||
off_t size;
|
||||
};
|
||||
|
||||
#define FILE_META_UNKNOWN ((struct file_meta){ .mtime = -1, .size = -1 })
|
||||
|
||||
struct cf_om_node *cf_om_root = NULL;
|
||||
static struct file_meta conffile_meta = { .mtime = -1, .size = -1 };
|
||||
static struct file_meta conffile_meta = FILE_META_UNKNOWN;
|
||||
|
||||
int cf_limbo = 1;
|
||||
struct config_main config;
|
||||
static struct file_meta config_meta = { .mtime = -1, .size = -1 };
|
||||
static struct file_meta config_meta = FILE_META_UNKNOWN;
|
||||
|
||||
static const char *conffile_path()
|
||||
{
|
||||
@ -53,6 +55,8 @@ static int get_meta(const char *path, struct file_meta *metap)
|
||||
if (stat(path, &st) == -1) {
|
||||
if (errno != ENOENT)
|
||||
return WHYF_perror("stat(%s)", path);
|
||||
// Do not return FILE_META_UNKNOWN on ENOENT, otherwise reload logic breaks. A non-existent
|
||||
// file is treated as size == 0.
|
||||
metap->size = 0;
|
||||
metap->mtime = -1;
|
||||
} else {
|
||||
@ -62,29 +66,37 @@ static int get_meta(const char *path, struct file_meta *metap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load()
|
||||
static int cmp_meta(const struct file_meta *a, const struct file_meta *b)
|
||||
{
|
||||
return a->mtime < b->mtime ? -1 : a->mtime > b->mtime ? 1 : a->size < b->size ? -1 : a->size > b->size ? 1 : 0;
|
||||
}
|
||||
|
||||
static int reload(const char *path, int *resultp)
|
||||
{
|
||||
const char *path = conffile_path();
|
||||
struct file_meta meta;
|
||||
if (get_meta(path, &meta) == -1)
|
||||
return CFERROR;
|
||||
if (get_meta(conffile_path(), &meta) == -1)
|
||||
return -1;
|
||||
if (cmp_meta(&meta, &conffile_meta) == 0)
|
||||
return 0;
|
||||
if (conffile_meta.mtime != -1)
|
||||
INFOF("config file %s -- detected new version", conffile_path());
|
||||
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;
|
||||
return -1;
|
||||
} else if (meta.size <= 0) {
|
||||
INFOF("config file %s is zero size", path);
|
||||
} else {
|
||||
FILE *f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
WHYF_perror("fopen(%s)", path);
|
||||
return CFERROR;
|
||||
return -1;
|
||||
}
|
||||
if ((buf = emalloc(meta.size)) == NULL) {
|
||||
fclose(f);
|
||||
return CFERROR;
|
||||
return -1;
|
||||
}
|
||||
if (fread(buf, meta.size, 1, f) != 1) {
|
||||
if (ferror(f))
|
||||
@ -93,60 +105,36 @@ static int load()
|
||||
WHYF("fread(%s, %llu) hit EOF", path, (unsigned long long) meta.size);
|
||||
free(buf);
|
||||
fclose(f);
|
||||
return CFERROR;
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) == EOF) {
|
||||
WHYF_perror("fclose(%s)", path);
|
||||
free(buf);
|
||||
return WHYF_perror("fclose(%s)", path);
|
||||
return -1;
|
||||
}
|
||||
INFOF("config file %s successfully read %ld bytes", path, (long) meta.size);
|
||||
}
|
||||
conffile_meta = meta;
|
||||
struct cf_om_node *new_root = NULL;
|
||||
int result = cf_om_parse(path, buf, meta.size, &new_root);
|
||||
*resultp = 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;
|
||||
if (*resultp == CFERROR)
|
||||
return -1;
|
||||
cf_om_free_node(&cf_om_root);
|
||||
cf_om_root = new_root;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int has_changed(const struct file_meta *metap)
|
||||
int cf_om_reload()
|
||||
{
|
||||
const char *path = conffile_path();
|
||||
struct file_meta meta;
|
||||
if (get_meta(path, &meta) == -1)
|
||||
return -1;
|
||||
return metap->size != meta.size || metap->mtime != meta.mtime;
|
||||
int result;
|
||||
return reload(conffile_path(), &result);
|
||||
}
|
||||
|
||||
int cf_om_load()
|
||||
{
|
||||
return load() == CFERROR ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Check if the config file has changed since we last read it, and if so, invalidate the buffer so
|
||||
* that the next call to read_config() will re-load it. Returns 1 if the buffer was invalidated, 0
|
||||
* if not, -1 on error.
|
||||
*
|
||||
* TODO: when the config system is overhauled to provide proper dynamic config reloading in JNI and
|
||||
* in the servald daemon, this method will become unnecessary.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int cf_om_reload()
|
||||
{
|
||||
switch (has_changed(&conffile_meta)) {
|
||||
case -1:
|
||||
return CFERROR;
|
||||
case 0:
|
||||
return CFOK;
|
||||
default:
|
||||
if (conffile_meta.mtime != -1)
|
||||
INFOF("config file %s -- detected new version", conffile_path());
|
||||
return cf_om_load();
|
||||
}
|
||||
conffile_meta = FILE_META_UNKNOWN;
|
||||
return cf_om_reload();
|
||||
}
|
||||
|
||||
int cf_om_save()
|
||||
@ -165,6 +153,7 @@ int cf_om_save()
|
||||
fprintf(outf, "%s=%s\n", it.node->fullkey, it.node->text);
|
||||
if (fclose(outf) == EOF)
|
||||
return WHYF_perror("fclose(%s)", tempfile);
|
||||
// rename(2) is atomic, so no other process will read a half-written file.
|
||||
if (rename(tempfile, path)) {
|
||||
WHYF_perror("rename(%s, %s)", tempfile, path);
|
||||
unlink(tempfile);
|
||||
@ -182,69 +171,66 @@ int cf_om_save()
|
||||
int cf_init()
|
||||
{
|
||||
cf_limbo = 1;
|
||||
conffile_meta = config_meta = FILE_META_UNKNOWN;
|
||||
memset(&config, 0, sizeof config);
|
||||
if (cf_dfl_config_main(&config) == CFERROR)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_and_parse(int permissive)
|
||||
static int reload_and_parse(int permissive)
|
||||
{
|
||||
int result = CFOK;
|
||||
if (cf_limbo)
|
||||
result = cf_dfl_config_main(&config);
|
||||
if (result == CFOK) {
|
||||
result = load();
|
||||
if (result == CFOK || result == CFEMPTY) {
|
||||
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) {
|
||||
if (reload(conffile_path(), &result) == -1)
|
||||
result = CFERROR;
|
||||
else if (!cf_limbo && cmp_meta(&conffile_meta, &config_meta) == 0)
|
||||
return 0;
|
||||
else {
|
||||
config_meta = conffile_meta;
|
||||
if (result == CFOK || result == CFEMPTY) {
|
||||
struct config_main new_config;
|
||||
memset(&new_config, 0, sizeof new_config);
|
||||
result = cf_dfl_config_main(&new_config);
|
||||
if (result == CFOK || result == CFEMPTY) {
|
||||
result = CFOK;
|
||||
config = new_config;
|
||||
config_meta = conffile_meta;
|
||||
cf_limbo = 0;
|
||||
logFlush();
|
||||
} else if (result != CFERROR) {
|
||||
result &= ~CFEMPTY;
|
||||
config = new_config;
|
||||
WARN("limping along with incomplete configuration");
|
||||
cf_limbo = 0;
|
||||
result = cf_om_root ? cf_opt_config_main(&new_config, cf_om_root) : CFEMPTY;
|
||||
if (result == CFOK || result == CFEMPTY) {
|
||||
result = CFOK;
|
||||
config = new_config;
|
||||
} else if (result != CFERROR) {
|
||||
result &= ~CFEMPTY;
|
||||
config = new_config;
|
||||
WARN("limping along with incomplete configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == CFOK)
|
||||
return 0;
|
||||
cf_limbo = 0; // let log messages out
|
||||
strbuf b = strbuf_alloca(180);
|
||||
strbuf_cf_flag_reason(b, result);
|
||||
if (!permissive)
|
||||
return WHYF("config file %s not loaded -- %s", conffile_path(), strbuf_str(b));
|
||||
WARNF("config file %s loaded despite problems -- %s", conffile_path(), strbuf_str(b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload_and_parse(int permissive)
|
||||
{
|
||||
if (!cf_limbo && cf_om_root) {
|
||||
if (!has_changed(&config_meta))
|
||||
return 0;
|
||||
INFOF("config file %s reloading", conffile_path());
|
||||
// Let log messages out.
|
||||
cf_limbo = 0;
|
||||
logFlush();
|
||||
if (result != CFOK) {
|
||||
strbuf b = strbuf_alloca(180);
|
||||
strbuf_cf_flag_reason(b, result);
|
||||
if (!permissive)
|
||||
return WHYF("config file %s not loaded -- %s", conffile_path(), strbuf_str(b));
|
||||
WARNF("config file %s loaded despite problems -- %s", conffile_path(), strbuf_str(b));
|
||||
}
|
||||
return load_and_parse(permissive);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cf_load()
|
||||
{
|
||||
return load_and_parse(0);
|
||||
conffile_meta = config_meta = FILE_META_UNKNOWN;
|
||||
return reload_and_parse(0);
|
||||
}
|
||||
|
||||
int cf_load_permissive()
|
||||
{
|
||||
return load_and_parse(1);
|
||||
conffile_meta = config_meta = FILE_META_UNKNOWN;
|
||||
return reload_and_parse(1);
|
||||
}
|
||||
|
||||
int cf_reload()
|
||||
|
@ -117,6 +117,9 @@ schedule(&_sched_##X); }
|
||||
/* Periodically check for server shut down */
|
||||
SCHEDULE(server_shutdown_check, 0, 100);
|
||||
|
||||
/* Periodically reload configuration */
|
||||
SCHEDULE(server_config_reload, SERVER_CONFIG_RELOAD_INTERVAL_MS, SERVER_CONFIG_RELOAD_INTERVAL_MS + 100);
|
||||
|
||||
/* Setup up MDP & monitor interface unix domain sockets */
|
||||
overlay_mdp_setup_sockets();
|
||||
monitor_setup_sockets();
|
||||
|
3
serval.h
3
serval.h
@ -164,6 +164,8 @@ int create_serval_instance_dir();
|
||||
int form_serval_instance_path(char *buf, size_t bufsiz, const char *path);
|
||||
void serval_setinstancepath(const char *instancepath);
|
||||
|
||||
#define SERVER_CONFIG_RELOAD_INTERVAL_MS 1000
|
||||
|
||||
extern int serverMode;
|
||||
extern int servalShutdown;
|
||||
|
||||
@ -710,6 +712,7 @@ int fd_poll();
|
||||
void overlay_interface_discover(struct sched_ent *alarm);
|
||||
void overlay_dummy_poll(struct sched_ent *alarm);
|
||||
void overlay_route_tick(struct sched_ent *alarm);
|
||||
void server_config_reload(struct sched_ent *alarm);
|
||||
void server_shutdown_check(struct sched_ent *alarm);
|
||||
void overlay_mdp_poll(struct sched_ent *alarm);
|
||||
int overlay_mdp_try_interal_services(overlay_mdp_frame *mdp);
|
||||
|
29
server.c
29
server.c
@ -87,8 +87,8 @@ void server_save_argv(int argc, const char *const *argv)
|
||||
|
||||
int server(char *backing_file)
|
||||
{
|
||||
/* For testing, it can be very helpful to delay the start of the server
|
||||
process, for example to check that the start/stop logic is robust.
|
||||
/* For testing, it can be very helpful to delay the start of the server process, for example to
|
||||
* check that the start/stop logic is robust.
|
||||
*/
|
||||
const char *delay = getenv("SERVALD_SERVER_START_DELAY");
|
||||
if (delay)
|
||||
@ -125,8 +125,7 @@ int server(char *backing_file)
|
||||
FILE *f=fopen(filename,"w");
|
||||
if (!f) {
|
||||
WHY_perror("fopen");
|
||||
WHYF("Could not write to PID file %s", filename);
|
||||
return -1;
|
||||
return WHYF("Could not write to PID file %s", filename);
|
||||
}
|
||||
server_getpid = getpid();
|
||||
fprintf(f,"%d\n", server_getpid);
|
||||
@ -137,6 +136,28 @@ int server(char *backing_file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called periodically by the server process in its main loop.
|
||||
*/
|
||||
void server_config_reload(struct sched_ent *alarm)
|
||||
{
|
||||
switch (cf_reload()) {
|
||||
case -1:
|
||||
WARN("server continuing with prior config");
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
INFO("server config successfully reloaded");
|
||||
break;
|
||||
}
|
||||
if (alarm) {
|
||||
time_ms_t now = gettime_ms();
|
||||
alarm->alarm = now + SERVER_CONFIG_RELOAD_INTERVAL_MS;
|
||||
alarm->deadline = alarm->alarm + 1000;
|
||||
schedule(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called periodically by the server process in its main loop.
|
||||
*/
|
||||
void server_shutdown_check(struct sched_ent *alarm)
|
||||
|
Loading…
Reference in New Issue
Block a user