mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-07 11:08:36 +00:00
Expose daemon's primary SID in 'proc/primary_sid'
This helps tests distinguish which of a daemon's keyring identities is used as its primary identity, which is not otherwise obvious without consulting the routing table, because slots are allocated in random order.
This commit is contained in:
parent
798e34cc5b
commit
1a091aa8a1
@ -1502,10 +1502,11 @@ static keyring_identity *keyring_new_identity()
|
||||
|
||||
keyring_identity *keyring_inmemory_identity(){
|
||||
keyring_identity *id = keyring_new_identity();
|
||||
keyring_finalise_identity(NULL, id);
|
||||
if (id)
|
||||
if (id) {
|
||||
keyring_finalise_identity(NULL, id);
|
||||
add_subscriber(id);
|
||||
INFOF("created in-memory identity SID=%s", alloca_tohex_sid_t(id->subscriber->sid));
|
||||
INFOF("created in-memory identity SID=%s", alloca_tohex_sid_t(id->subscriber->sid));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
Serval DNA MDP addressing
|
||||
Copyright (C) 2016-2018 Flinders University
|
||||
Copyright (C) 2012-2015 Serval Project Inc.
|
||||
Copyright (C) 2012 Paul Gardner-Stephen
|
||||
|
||||
@ -28,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "lang.h" // for bool_t
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "keyring.h"
|
||||
@ -54,37 +56,64 @@ static struct broadcast bpilist[MAX_BPIS];
|
||||
|
||||
static __thread struct tree_root root={.index_size_bytes=SID_SIZE};
|
||||
|
||||
static __thread struct subscriber *my_subscriber=NULL;
|
||||
static __thread bool_t primary_sid_written = 0;
|
||||
static __thread struct subscriber *primary_sid = NULL;
|
||||
static __thread struct subscriber *my_subscriber = NULL;
|
||||
|
||||
struct subscriber *get_my_subscriber(bool_t create){
|
||||
struct subscriber *get_my_subscriber(bool_t create)
|
||||
{
|
||||
if (!serverMode)
|
||||
return NULL;
|
||||
assert(keyring != NULL);
|
||||
if (my_subscriber && my_subscriber->reachable != REACHABLE_SELF)
|
||||
my_subscriber = NULL;
|
||||
if (!my_subscriber){
|
||||
keyring_identity *id = keyring->identities;
|
||||
while(id){
|
||||
if (id->subscriber->reachable == REACHABLE_SELF){
|
||||
// Look for a reachable self-identity in the keyring.
|
||||
if (!my_subscriber) {
|
||||
assert(keyring != NULL);
|
||||
keyring_identity *id;
|
||||
for (id = keyring->identities; id; id = id->next)
|
||||
if (id->subscriber->reachable == REACHABLE_SELF) {
|
||||
my_subscriber = id->subscriber;
|
||||
return my_subscriber;
|
||||
break;
|
||||
}
|
||||
id = id->next;
|
||||
}
|
||||
// If there is no reachable self-identity in the keyring, then roll one in-memory, which will
|
||||
// persist until the server terminates.
|
||||
if (create){
|
||||
id = keyring_inmemory_identity();
|
||||
}
|
||||
// If there is no reachable self-identity in the keyring, then roll one in-memory, which will
|
||||
// persist until the server terminates.
|
||||
if (!my_subscriber && create) {
|
||||
keyring_identity *id = keyring_inmemory_identity();
|
||||
if (id)
|
||||
my_subscriber = id->subscriber;
|
||||
}
|
||||
// Normally, the server creates files in proc/ before it creates its pidfile, and does not modify
|
||||
// those files while running. This avoids any race conditions with other processes that read the
|
||||
// files. In this case, the proc/primary_sid file is written _after_ the pidfile, and could
|
||||
// potentially be re-written while running (eg, if the primary identity is deleted, causing the
|
||||
// server to choose another). Potential race conditions are avoided because (1) the size of the
|
||||
// file never alters, and (2) the server_write_proc_state() function overwrites any existing
|
||||
// content using a single, indivisible write(2) system call.
|
||||
if (!primary_sid_written || primary_sid != my_subscriber) {
|
||||
primary_sid = my_subscriber;
|
||||
if (my_subscriber) {
|
||||
const char *sidhex = alloca_tohex_sid_t(primary_sid->sid);
|
||||
server_write_proc_state("primary_sid", "%s", sidhex);
|
||||
INFOF("PRIMARY IDENTITY sid=%s", sidhex);
|
||||
}
|
||||
else {
|
||||
server_unlink_proc_state("primary_sid");
|
||||
INFOF("NO PRIMARY IDENTITY");
|
||||
}
|
||||
primary_sid_written = 1;
|
||||
}
|
||||
return my_subscriber;
|
||||
}
|
||||
|
||||
void release_my_subscriber(){
|
||||
void release_my_subscriber()
|
||||
{
|
||||
if (my_subscriber && my_subscriber->identity->slot==0)
|
||||
keyring_free_identity(my_subscriber->identity);
|
||||
server_unlink_proc_state("primary_sid");
|
||||
my_subscriber = NULL;
|
||||
primary_sid = NULL;
|
||||
primary_sid_written = 0;
|
||||
}
|
||||
|
||||
static int free_node(void **record, void *UNUSED(context))
|
||||
@ -98,6 +127,8 @@ static int free_node(void **record, void *UNUSED(context))
|
||||
alloca_tohex_sid_t(subscriber->sid), subscriber->sync_state);
|
||||
if (subscriber->identity)
|
||||
FATAL("Can't free a subscriber that is unlocked in the keyring");
|
||||
if (subscriber == my_subscriber)
|
||||
FATAL("Can't free a subscriber that is the primary identity");
|
||||
free(subscriber);
|
||||
*record=NULL;
|
||||
return 0;
|
||||
|
77
server.c
77
server.c
@ -77,7 +77,6 @@ static void serverCleanUp();
|
||||
static const char *_server_pidfile_path(struct __sourceloc __whence);
|
||||
#define server_pidfile_path() (_server_pidfile_path(__WHENCE__))
|
||||
|
||||
static int server_write_proc_state(const char *path, const char *fmt, ...);
|
||||
static int server_get_proc_state(const char *path, char *buff, size_t buff_len);
|
||||
static void server_stop_alarms();
|
||||
|
||||
@ -343,6 +342,9 @@ static int server_write_pid()
|
||||
server_write_proc_state("http_port", "%d", httpd_server_port);
|
||||
server_write_proc_state("mdp_inet_port", "%d", mdp_loopback_port);
|
||||
|
||||
// Create or unlink the "primary_sid" proc state file.
|
||||
get_my_subscriber(0);
|
||||
|
||||
// Create a locked pidfile to advertise that the server is now running.
|
||||
const char *pidfile_path = server_pidfile_path();
|
||||
if (pidfile_path == NULL)
|
||||
@ -452,29 +454,46 @@ static int get_proc_path(const char *path, char *buf, size_t bufsiz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int server_write_proc_state(const char *path, const char *fmt, ...)
|
||||
int server_write_proc_state(const char *path, const char *fmt, ...)
|
||||
{
|
||||
char path_buf[400];
|
||||
if (get_proc_path(path, path_buf, sizeof path_buf)==-1)
|
||||
return -1;
|
||||
|
||||
// Create the directory that contains the path, if it does not already exist.
|
||||
size_t dirsiz = strlen(path_buf) + 1;
|
||||
char dir_buf[dirsiz];
|
||||
strcpy(dir_buf, path_buf);
|
||||
const char *dir = dirname(dir_buf); // modifies dir_buf[]
|
||||
if (mkdirs_info(dir, 0700) == -1)
|
||||
return WHY_perror("mkdirs()");
|
||||
if (emkdirs_info(dir, 0700) == -1)
|
||||
return -1;
|
||||
|
||||
// Format the file's new content in a local buffer on the stack.
|
||||
strbuf sb;
|
||||
STRBUF_ALLOCA_FIT(sb, 1024, strbuf_va_printf(sb, fmt));
|
||||
|
||||
FILE *f = fopen(path_buf, "w");
|
||||
if (!f)
|
||||
return WHY_perror("fopen()");
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(f, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fclose(f);
|
||||
// Overwrite the file, creating it if necessary, using a single write(2) system call, followed by
|
||||
// a ftruncate(2) system call (in case the file already existed and was longer than its new
|
||||
// content). This allows potential race conditions to be avoided for files that are overwritten
|
||||
// while the server runs, as long as the written contents are always the same size, or always
|
||||
// contain a terminating sequence (eg, newline).
|
||||
int fd = open(path_buf, O_CREAT | O_WRONLY, 0700);
|
||||
if (fd == -1)
|
||||
return WHYF_perror("open(%s, O_CREAT|O_WRONLY, 0700)", alloca_str_toprint(path_buf));
|
||||
int ret = write_all(fd, strbuf_str(sb), strbuf_len(sb));
|
||||
if (ret != -1 && (ret = ftruncate(fd, strbuf_len(sb)) == -1))
|
||||
ret = WHYF_perror("ftruncate(%s, %zu)", alloca_str_toprint(path_buf), strbuf_len(sb));
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int server_unlink_proc_state(const char *path)
|
||||
{
|
||||
char path_buf[400];
|
||||
if (get_proc_path(path, path_buf, sizeof path_buf)==-1)
|
||||
return -1;
|
||||
if (unlink(path) == -1 && errno != ENOENT)
|
||||
return WHYF_perror("unlink(%s)", alloca_str_toprint(path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -483,16 +502,20 @@ static int server_get_proc_state(const char *path, char *buff, size_t buff_len)
|
||||
char path_buf[400];
|
||||
if (get_proc_path(path, path_buf, sizeof path_buf)==-1)
|
||||
return -1;
|
||||
|
||||
FILE *f = fopen(path_buf, "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
int ret=0;
|
||||
|
||||
if (!fgets(buff, buff_len, f))
|
||||
ret = WHY_perror("fgets");
|
||||
|
||||
if (!f) {
|
||||
if (errno != ENOENT)
|
||||
return WHYF_perror("fopen(%s)", alloca_str_toprint(path_buf));
|
||||
return 1;
|
||||
}
|
||||
int ret = 0;
|
||||
errno = 0; // fgets() does not set errno on end-of-file
|
||||
if (!fgets(buff, buff_len, f)) {
|
||||
if (errno)
|
||||
ret = WHYF_perror("fgets from %s", alloca_str_toprint(path_buf));
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
@ -788,11 +811,15 @@ static void cli_server_details(struct cli_context *context, const struct pid_tid
|
||||
cli_put_long(context, id->tid, "\n");
|
||||
}
|
||||
char buff[256];
|
||||
if (server_get_proc_state("http_port", buff, sizeof buff)!=-1){
|
||||
if (server_get_proc_state("primary_sid", buff, sizeof buff) == 0){
|
||||
cli_field_name(context, "primary_sid", ":");
|
||||
cli_put_string(context, buff, "\n");
|
||||
}
|
||||
if (server_get_proc_state("http_port", buff, sizeof buff) == 0){
|
||||
cli_field_name(context, "http_port", ":");
|
||||
cli_put_string(context, buff, "\n");
|
||||
}
|
||||
if (server_get_proc_state("mdp_inet_port", buff, sizeof buff)!=-1){
|
||||
if (server_get_proc_state("mdp_inet_port", buff, sizeof buff) == 0){
|
||||
cli_field_name(context, "mdp_inet_port", ":");
|
||||
cli_put_string(context, buff, "\n");
|
||||
}
|
||||
|
3
server.h
3
server.h
@ -49,6 +49,9 @@ void server_close();
|
||||
|
||||
void server_loop(time_ms_t (*waiting)(time_ms_t, time_ms_t, time_ms_t), void (*wokeup)());
|
||||
|
||||
int server_write_proc_state(const char *path, const char *fmt, ...);
|
||||
int server_unlink_proc_state(const char *path);
|
||||
|
||||
void server_rhizome_add_bundle(uint64_t rowid);
|
||||
|
||||
DECLARE_TRIGGER(shutdown);
|
||||
|
16
testdefs.sh
16
testdefs.sh
@ -421,6 +421,22 @@ servald_start() {
|
||||
SERVALD_SERVER_CHDIR="$instance_dir" SERVALD_LOG_FILE="$instance_servald_log" $servald start "$@"
|
||||
}
|
||||
|
||||
# Utility function:
|
||||
# - fetch the daemon's primary SID
|
||||
get_servald_primary_sid() {
|
||||
local _instance="$2"
|
||||
[ -z "$_instance" ] || push_and_set_instance $_instance || return $?
|
||||
local _var="$1"
|
||||
local _sid=$(<"$SERVALINSTANCE_PATH/proc/primary_sid")
|
||||
assert --message="instance $instance_name primary SID is known" [ -n "$_sid" ]
|
||||
if [ -n "$_var" ]; then
|
||||
eval "$_var=\$_sid"
|
||||
tfw_log "$_var=$_sid"
|
||||
fi
|
||||
[ -z "$_instance" ] || pop_instance
|
||||
return 0
|
||||
}
|
||||
|
||||
# Utility function:
|
||||
# - test whether the daemon's HTTP server has started
|
||||
servald_http_server_started() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user