adds shutdownmode, in which calls are replied with defined err

based on a patch by Robert Szokovacs
sayer/1.4-spce2.6
Stefan Sayer 15 years ago
parent 8e2a4655eb
commit 7774944f12

@ -329,14 +329,21 @@ XMLRPC2DIServer::XMLRPC2DIServer(unsigned int port,
s(s), s(s),
// register method 'calls' // register method 'calls'
calls_method(s), calls_method(s),
// register method 'get_loglevel'
setloglevel_method(s),
// register method 'set_loglevel' // register method 'set_loglevel'
getloglevel_method(s) setloglevel_method(s),
// register method 'get_loglevel'
getloglevel_method(s),
// register method 'set_shutdownmode'
setshutdownmode_method(s),
// register method 'get_shutdownmode'
getshutdownmode_method(s)
{ {
DBG("XMLRPC Server: enabled builtin method 'calls'\n"); DBG("XMLRPC Server: enabled builtin method 'calls'\n");
DBG("XMLRPC Server: enabled builtin method 'get_loglevel'\n"); DBG("XMLRPC Server: enabled builtin method 'get_loglevel'\n");
DBG("XMLRPC Server: enabled builtin method 'set_loglevel'\n"); DBG("XMLRPC Server: enabled builtin method 'set_loglevel'\n");
DBG("XMLRPC Server: enabled builtin method 'get_shutdownmode'\n");
DBG("XMLRPC Server: enabled builtin method 'set_shutdownmode'\n");
// export all methods via 'di' function? // export all methods via 'di' function?
if (di_export) { if (di_export) {
@ -441,6 +448,18 @@ void XMLRPC2DIServerSetLoglevelMethod::execute(XmlRpcValue& params, XmlRpcValue&
result = "200 OK"; result = "200 OK";
} }
void XMLRPC2DIServerGetShutdownmodeMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
DBG("XMLRPC2DI: get_shutdownmode returns %s\n", AmConfig::ShutdownMode?"true":"false");
result = (bool)AmConfig::ShutdownMode;
}
void XMLRPC2DIServerSetShutdownmodeMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
AmConfig::ShutdownMode = params[0];
DBG("XMLRPC2DI: set shutdownmode to %s.\n", AmConfig::ShutdownMode?"true":"false");
result = "200 OK";
}
void XMLRPC2DIServerDIMethod::execute(XmlRpcValue& params, XmlRpcValue& result) { void XMLRPC2DIServerDIMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
try { try {
if (params.size() < 2) { if (params.size() < 2) {

@ -57,6 +57,9 @@ DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerCallsMethod, "calls");
DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerSetLoglevelMethod, "set_loglevel"); DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerSetLoglevelMethod, "set_loglevel");
DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetLoglevelMethod, "get_loglevel"); DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetLoglevelMethod, "get_loglevel");
DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerSetShutdownmodeMethod, "set_shutdownmode");
DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetShutdownmodeMethod, "get_shutdownmode");
class XMLRPC2DIServerDIMethod class XMLRPC2DIServerDIMethod
: public XmlRpcServerMethod { : public XmlRpcServerMethod {
@ -90,6 +93,8 @@ class XMLRPC2DIServer : public AmThread {
XMLRPC2DIServerCallsMethod calls_method; XMLRPC2DIServerCallsMethod calls_method;
XMLRPC2DIServerSetLoglevelMethod setloglevel_method; XMLRPC2DIServerSetLoglevelMethod setloglevel_method;
XMLRPC2DIServerGetLoglevelMethod getloglevel_method; XMLRPC2DIServerGetLoglevelMethod getloglevel_method;
XMLRPC2DIServerSetShutdownmodeMethod setshutdownmode_method;
XMLRPC2DIServerGetShutdownmodeMethod getshutdownmode_method;
XMLRPC2DIServerDIMethod* di_method; XMLRPC2DIServerDIMethod* di_method;
void registerMethods(const std::string& iface); void registerMethods(const std::string& iface);

@ -76,27 +76,35 @@ void AmSessionFactory::configureSession(AmSession* sess) {
void AmSessionFactory::onOoDRequest(const AmSipRequest& req) void AmSessionFactory::onOoDRequest(const AmSipRequest& req)
{ {
if(req.method == "OPTIONS"){
if (req.method == "OPTIONS") {
// Basic OPTIONS support // Basic OPTIONS support
if (!AmConfig::OptionsSessionLimit || if (AmConfig::OptionsSessionLimit &&
(AmSession::getSessionNum() < AmConfig::OptionsSessionLimit)) { (AmSession::getSessionNum() >= AmConfig::OptionsSessionLimit)) {
AmSipDialog::reply_error(req, 200, "OK");
} else {
// return error code if near to overload // return error code if near to overload
AmSipDialog::reply_error(req, AmSipDialog::reply_error(req,
AmConfig::OptionsSessionLimitErrCode, AmConfig::OptionsSessionLimitErrCode,
AmConfig::OptionsSessionLimitErrReason); AmConfig::OptionsSessionLimitErrReason);
return;
} }
if (AmConfig::ShutdownMode) {
// return error code if in shutdown mode
AmSipDialog::reply_error(req,
AmConfig::ShutdownModeErrCode,
AmConfig::ShutdownModeErrReason);
return; return;
}
AmSipDialog::reply_error(req, 200, "OK");
return;
} }
ERROR("sorry, we don't support beginning a new session with " ERROR("sorry, we don't support beginning a new session with "
"a '%s' message\n", req.method.c_str()); "a '%s' message\n", req.method.c_str());
AmSipDialog::reply_error(req,501,"Not Implemented"); AmSipDialog::reply_error(req,501,"Not Implemented");
return; return;
} }
// void AmSessionFactory::postEvent(AmEvent* ev) { // void AmSessionFactory::postEvent(AmEvent* ev) {

@ -94,6 +94,10 @@ unsigned int AmConfig::OptionsSessionLimit = 0;
unsigned int AmConfig::OptionsSessionLimitErrCode = 503; unsigned int AmConfig::OptionsSessionLimitErrCode = 503;
string AmConfig::OptionsSessionLimitErrReason = "Server overload"; string AmConfig::OptionsSessionLimitErrReason = "Server overload";
bool AmConfig::ShutdownMode = false;
unsigned int AmConfig::ShutdownModeErrCode = 503;
string AmConfig::ShutdownModeErrReason = "Server shutting down";
AmSipDialog::provisional_100rel AmConfig::rel100 = REL100_SUPPORTED; AmSipDialog::provisional_100rel AmConfig::rel100 = REL100_SUPPORTED;
vector <string> AmConfig::CodecOrder; vector <string> AmConfig::CodecOrder;
@ -487,6 +491,24 @@ int AmConfig::readConfiguration()
} }
} }
if(cfg.hasParameter("shutdown_mode_reply")){
string c_reply = cfg.getParameter("shutdown_mode_reply");
size_t spos = c_reply.find(" ");
if (spos == string::npos || spos == c_reply.length()) {
ERROR("invalid shutdown_mode_reply specified, expected \"<code> <reason>\","
"e.g. shutdown_mode_reply=\"503 Not At The Moment, Please\".\n");
ret = -1;
} else {
if (str2i(c_reply.substr(0, spos), ShutdownModeErrCode)) {
ERROR("invalid shutdown_mode_reply specified, expected \"<code> <reason>\","
"e.g. shutdown_mode_reply=\"503 Not At The Moment, Please\".\n");
ret = -1;
}
ShutdownModeErrReason = c_reply.substr(spos+1);
}
}
if (cfg.hasParameter("100rel")) { if (cfg.hasParameter("100rel")) {
string rel100s = cfg.getParameter("100rel"); string rel100s = cfg.getParameter("100rel");
if (rel100s == "disabled" || rel100s == "off") { if (rel100s == "disabled" || rel100s == "off") {

@ -162,6 +162,10 @@ struct AmConfig
static unsigned int OptionsSessionLimitErrCode; static unsigned int OptionsSessionLimitErrCode;
static string OptionsSessionLimitErrReason; static string OptionsSessionLimitErrReason;
static bool ShutdownMode;
static unsigned int ShutdownModeErrCode;
static string ShutdownModeErrReason;
static AmSipDialog::provisional_100rel rel100; static AmSipDialog::provisional_100rel rel100;
/** Time of no RTP after which Session is regarded as dead, 0 for no Timeout */ /** Time of no RTP after which Session is regarded as dead, 0 for no Timeout */

@ -367,6 +367,15 @@ bool AmSessionContainer::postEvent(const string& local_tag,
AmSession* AmSessionContainer::createSession(AmSipRequest& req, AmSession* AmSessionContainer::createSession(AmSipRequest& req,
AmArg* session_params) AmArg* session_params)
{ {
if (AmConfig::ShutdownMode) {
_run_cond.set(true); // so that thread stops
DBG("Shutdown mode. Not creating session.\n");
AmSipDialog::reply_error(req,AmConfig::ShutdownModeErrCode,
AmConfig::ShutdownModeErrReason);
return NULL;
}
if (AmConfig::SessionLimit && if (AmConfig::SessionLimit &&
AmConfig::SessionLimit <= AmSession::session_num) { AmConfig::SessionLimit <= AmSession::session_num) {

@ -228,15 +228,6 @@ stderr=no
# (same as -D) # (same as -D)
loglevel=2 loglevel=2
# optional parameter: max_shutdown_time=<time in seconds>
#
# Limit on server shutdown time (time to send/resend BYE
# to active calls). 0 to disable (infinite).
#
# Default: 10
#
#max_shutdown_time = 10
# optional parameter: syslog_facility={DAEMON|USER|LOCAL[0-7]} # optional parameter: syslog_facility={DAEMON|USER|LOCAL[0-7]}
# #
# - sets the log facility that is used for syslog. Using this, # - sets the log facility that is used for syslog. Using this,
@ -266,6 +257,22 @@ loglevel=2
# #
# log_events=yes # log_events=yes
# optional parameter: max_shutdown_time=<time in seconds>
#
# Limit on server shutdown time (time to send/resend BYE
# to active calls). 0 to disable (infinite).
#
# Default: 10
#
#max_shutdown_time = 10
# optional parameter: shutdown_mode_reply="<code> <reason>"
#
# Error reply that is used as reply to INVITE and OPTION
# when SEMS is shutting down.
#
# Default: shutdown_mode_reply="503 Server shutting down"
############################################################ ############################################################
# tuning # tuning

@ -292,8 +292,13 @@ int StatsUDPServer::execute(char* msg_buf, string& reply,
"which - print available commands\n" "which - print available commands\n"
"set_loglevel <loglevel> - set log level\n" "set_loglevel <loglevel> - set log level\n"
"get_loglevel - get log level\n" "get_loglevel - get log level\n"
"\n" "set_shutdownmode <1 or 0> - turns on and off shutdown mode\n"
"get_shutdownmode - returns the shutdown mode's current state\n"
"DI <factory> <function> (<args>)* - invoke DI command\n" "DI <factory> <function> (<args>)* - invoke DI command\n"
"\n"
"When in shutdown mode, SEMS will answer with the configured 5xx errorcode to\n"
"new INVITE and OPTIONS requests.\n"
; ;
} }
else if (cmd_str.length() > 4 && cmd_str.substr(0, 4) == "set_") { else if (cmd_str.length() > 4 && cmd_str.substr(0, 4) == "set_") {
@ -305,6 +310,25 @@ int StatsUDPServer::execute(char* msg_buf, string& reply,
reply= "loglevel set to "+int2str(log_level)+".\n"; reply= "loglevel set to "+int2str(log_level)+".\n";
} }
else if (cmd_str.substr(4, 12) == "shutdownmode") {
int tmp;
if(sscanf(&cmd_str.c_str()[17],"%u",&tmp) != 1)
reply= "invalid shutdownmode\n";
else
{
if(tmp)
{
AmConfig::ShutdownMode = true;
reply= "Shutdownmode activated!\n";
}
else
{
AmConfig::ShutdownMode = false;
reply= "Shutdownmode deactivated!\n";
}
}
}
else reply = "Unknown command: '" + cmd_str + "'\n"; else reply = "Unknown command: '" + cmd_str + "'\n";
} }
else if (cmd_str.length() > 4 && cmd_str.substr(0, 4) == "get_") { else if (cmd_str.length() > 4 && cmd_str.substr(0, 4) == "get_") {
@ -313,6 +337,17 @@ int StatsUDPServer::execute(char* msg_buf, string& reply,
reply= "loglevel is "+int2str(log_level)+".\n"; reply= "loglevel is "+int2str(log_level)+".\n";
} }
else if (cmd_str.substr(4, 12) == "shutdownmode") {
if(AmConfig::ShutdownMode)
{
reply= "Shutdownmode active!\n";
}
else
{
reply= "Shutdownmode inactive!\n";
}
}
else reply = "Unknown command: '" + cmd_str + "'\n"; else reply = "Unknown command: '" + cmd_str + "'\n";
} }
else if (cmd_str.length() > 4 && cmd_str.substr(0, 3) == "DI ") { else if (cmd_str.length() > 4 && cmd_str.substr(0, 3) == "DI ") {

@ -2,8 +2,8 @@ xmlrpc2di: DI call via XMLRPC
This module makes the Dynamic Invocation (DI) Interfaces exported This module makes the Dynamic Invocation (DI) Interfaces exported
by component modules accessible from XMLRPC. Additionaly the builtin by component modules accessible from XMLRPC. Additionaly the builtin
methods calls, get_loglevel and set_loglevel are implemented (like in the methods "calls", "get_loglevel"/"set_loglevel" and
stats UDP server). "get_shutdownmode"/"set_shutdownmode" are implemented.
Additionally, it can be used as client to access XMLRPC servers. Applications Additionally, it can be used as client to access XMLRPC servers. Applications
can use the DI function newConnection to add a new server entry, and sendRequest can use the DI function newConnection to add a new server entry, and sendRequest
@ -11,20 +11,9 @@ to send a request. If sendRequest is executed, an active server is selected from
the list and used to send the request. If sending the request failes, the server the list and used to send the request. If sending the request failes, the server
is put inactive for a (configurable) while, and only then retried. is put inactive for a (configurable) while, and only then retried.
This module uses the XmlRpc++ library (http://xmlrpcpp.sourceforge.net/). This module uses the XmlRpc++ library (http://xmlrpcpp.sourceforge.net/), which
In order to compile it, the xmlrpc library is needed; install it by is included, as it is currently not any more maintained by the major distributions.
make install-xmlrpcpp, or by hand: Some patches have been applied to that library (multi threading, SSL etc).
cd apps/examples/xmlrpc2di
wget http://switch.dl.sourceforge.net/sourceforge/xmlrpcpp/xmlrpc++0.7.tar.gz
&& tar xzvf xmlrpc++0.7.tar.gz
A small patch set needs to be applied as well:
patch -p0 < xmlrpcpp07_sems.patch
If xmlrpcpp is extracted to a different directory, the path in
the Makefile needs to be adapted. If your xmlrpc++ installation has the
SSL for xmlrpc client option, you may need to add -DHAVE_XMLRPCPP_SSL
to module_cflags due to some ambiguity in the header.
The XMLRPC server can be configured to run as single threaded server (if The XMLRPC server can be configured to run as single threaded server (if
one request is executed, the next ones have to wait), or a multi-threaded server one request is executed, the next ones have to wait), or a multi-threaded server
@ -38,6 +27,8 @@ Configuration parameters
function default description function default description
+--------------------------------------- +---------------------------------------
server_ip ANY if set, bind only to the specific interface
xmlrpc_port 8090 port to bind XMLRPC server to xmlrpc_port 8090 port to bind XMLRPC server to
export_di yes enable 'di' function (see below) export_di yes enable 'di' function (see below)

Loading…
Cancel
Save