From 52da7778cdd0a10b02a85006eccde1996796efd6 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 11 Jun 2014 13:43:56 +0930 Subject: [PATCH] Allow closing a monitor connection to force the server to quit --- constants.h | 1 + monitor.c | 17 +++++++++++++---- route_link.c | 2 ++ server.c | 14 ++++++++------ server.h | 3 +++ tests/server | 11 +++++++++++ vomp_console.c | 24 ++++++++++++++++++++++++ 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/constants.h b/constants.h index 4e884098..74ddad2e 100644 --- a/constants.h +++ b/constants.h @@ -102,6 +102,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define MONITOR_PEERS (1<<2) #define MONITOR_DNAHELPER (1<<3) #define MONITOR_LINKS (1<<4) +#define MONITOR_QUIT (1<<5) #define MAX_SIGNATURES 16 diff --git a/monitor.c b/monitor.c index fab9f9f3..8997ab18 100644 --- a/monitor.c +++ b/monitor.c @@ -64,6 +64,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "monitor-client.h" #include "socket.h" #include "dataformats.h" +#include "server.h" #ifdef HAVE_UCRED_H #include @@ -166,6 +167,10 @@ void monitor_poll(struct sched_ent *alarm) static void monitor_close(struct monitor_context *c){ INFOF("Tearing down monitor client fd=%d", c->alarm.poll.fd); + if (serverMode && c->flags & MONITOR_QUIT){ + INFOF("Quitting due to client disconnecting"); + serverMode=SERVER_CLOSING; + } unwatch(&c->alarm); close(c->alarm.poll.fd); c->alarm.poll.fd=-1; @@ -402,16 +407,18 @@ static int monitor_set(const struct cli_parsed *parsed, struct cli_context *cont if (codec>=0 && codec <=255) set_codec_flag(codec, c->supported_codecs); } - }else if (strcase_startswith(parsed->args[1],"rhizome", NULL)) + }else if (strcase_startswith(parsed->args[1],"rhizome", NULL)){ c->flags|=MONITOR_RHIZOME; - else if (strcase_startswith(parsed->args[1],"peers", NULL)){ + }else if (strcase_startswith(parsed->args[1],"peers", NULL)){ c->flags|=MONITOR_PEERS; enum_subscribers(NULL, monitor_announce_all_peers, NULL); - }else if (strcase_startswith(parsed->args[1],"dnahelper", NULL)) + }else if (strcase_startswith(parsed->args[1],"dnahelper", NULL)){ c->flags|=MONITOR_DNAHELPER; - else if (strcase_startswith(parsed->args[1],"links", NULL)){ + }else if (strcase_startswith(parsed->args[1],"links", NULL)){ c->flags|=MONITOR_LINKS; link_state_announce_links(); + }else if (strcase_startswith(parsed->args[1],"quit", NULL)){ + c->flags|=MONITOR_QUIT; }else return monitor_write_error(c,"Unknown monitor type"); @@ -435,6 +442,8 @@ static int monitor_clear(const struct cli_parsed *parsed, struct cli_context *co c->flags&=~MONITOR_DNAHELPER; else if (strcase_startswith(parsed->args[1],"links", NULL)) c->flags&=~MONITOR_LINKS; + else if (strcase_startswith(parsed->args[1],"quit", NULL)) + c->flags&=~MONITOR_QUIT; else return monitor_write_error(c,"Unknown monitor type"); diff --git a/route_link.c b/route_link.c index 099c56cb..cb6c3d27 100644 --- a/route_link.c +++ b/route_link.c @@ -485,6 +485,8 @@ static int monitor_announce(struct subscriber *subscriber, void *UNUSED(context) int link_state_announce_links(){ enum_subscribers(NULL, monitor_announce, NULL); + // announce ourselves as unreachable, mainly so that monitor clients will always get one link back + monitor_announce_link(0, NULL, my_subscriber); return 0; } diff --git a/server.c b/server.c index e75eb7f5..8b31eb85 100644 --- a/server.c +++ b/server.c @@ -95,7 +95,7 @@ const char *_server_pidfile_path(struct __sourceloc __whence) int server() { IN(); - serverMode = 1; + serverMode = SERVER_RUNNING; // Warn, not merely Info, if there is no configured log file. logLevel_NoLogFileConfigured = LOG_LEVEL_WARN; @@ -158,16 +158,18 @@ int server() // log message used by tests to wait for the server to start INFO("Server initialised, entering main loop"); - while (serverMode == 1 && fd_poll()) + + /* Check for activitiy and respond to it */ + while((serverMode==SERVER_RUNNING) && fd_poll()) ; serverCleanUp(); - + /* It is safe to unlink the pidfile here without checking whether it actually contains our own * PID, because server_shutdown_check() will have been executed very recently (in fd_poll()), so * if the code reaches here, the check has been done recently. */ server_unlink_pid(); - + serverMode = 0; RETURN(0); OUT(); } @@ -457,9 +459,9 @@ void signal_handler(int signal) /* Trigger the server to close gracefully after any current alarm has completed. If we get a second signal, exit now. */ - if (serverMode==1){ + if (serverMode==SERVER_RUNNING){ INFO("Attempting clean shutdown"); - serverMode=2; + serverMode=SERVER_CLOSING; return; } default: diff --git a/server.h b/server.h index fb96d7a9..fdfa0cae 100644 --- a/server.h +++ b/server.h @@ -19,6 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __SERVAL_DNA__SERVER_H #define __SERVAL_DNA__SERVER_H +#define SERVER_RUNNING 1 +#define SERVER_CLOSING 2 + DECLARE_ALARM(server_shutdown_check); DECLARE_ALARM(server_watchdog); DECLARE_ALARM(server_config_reload); diff --git a/tests/server b/tests/server index 81925c5e..6ca78a00 100755 --- a/tests/server +++ b/tests/server @@ -150,6 +150,17 @@ test_RemovePid() { wait_until ! kill -0 $servald_pid 2>/dev/null } +doc_MonitorQuit="Server stops due to monitor client disconnection" +setup_MonitorQuit() { + setup + start_servald_server +} +test_MonitorQuit() { + executeOk_servald console < <(sleep 1 && echo "monitor quit" && sleep 1) + tfw_cat --stdout --stderr + wait_until ! kill -0 $servald_pid 2>/dev/null +} + doc_NoZombie="Server process does not become a zombie" setup_NoZombie() { setup diff --git a/vomp_console.c b/vomp_console.c index 50b9f406..2e09fc14 100644 --- a/vomp_console.c +++ b/vomp_console.c @@ -71,6 +71,8 @@ static int console_hangup(const struct cli_parsed *parsed, struct cli_context *c static int console_audio(const struct cli_parsed *parsed, struct cli_context *context); static int console_usage(const struct cli_parsed *parsed, struct cli_context *context); static int console_quit(const struct cli_parsed *parsed, struct cli_context *context); +static int console_set(const struct cli_parsed *parsed, struct cli_context *context); +static int console_clear(const struct cli_parsed *parsed, struct cli_context *context); static void monitor_read(struct sched_ent *alarm); struct cli_schema console_commands[]={ @@ -80,6 +82,8 @@ struct cli_schema console_commands[]={ {console_usage,{"help",NULL},0,"This usage message"}, {console_audio,{"say","...",NULL},0,"Send a text string to the other party"}, {console_quit,{"quit",NULL},0,"Exit process"}, + {console_set,{"monitor","",NULL},0,"Set an arbitrary monitor flag"}, + {console_clear,{"ignore","",NULL},0,"Clear an arbitrary monitor flag"}, {NULL, {NULL, NULL, NULL}, 0, NULL}, }; @@ -315,6 +319,26 @@ static int console_quit(const struct cli_parsed *UNUSED(parsed), struct cli_cont return 0; } +static int console_set(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context)) +{ + const char *flag; + if (cli_arg(parsed, "flag", &flag, NULL, NULL) != -1){ + monitor_client_writeline(monitor_alarm.poll.fd, "monitor %s\n", + flag); + } + return 0; +} + +static int console_clear(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context)) +{ + const char *flag; + if (cli_arg(parsed, "flag", &flag, NULL, NULL) != -1){ + monitor_client_writeline(monitor_alarm.poll.fd, "ignore %s\n", + flag); + } + return 0; +} + static int console_audio(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) { if (!calls){