laforge
/
openbts-osmo
Archived
1
0
Fork 0

Catch SIGINT, SIGTERM and SIGHUP and shutdown the server gracefully.

master
Alexander Chemeris 12 years ago committed by Thomas Tsou
parent 163290b60e
commit 8598e72800
  1. 1
      public-trunk/CLI/CLI.cpp
  2. 100
      public-trunk/CLI/CLIParser.cpp
  3. 7
      public-trunk/CLI/CLIParser.h
  4. 56
      public-trunk/apps/OpenBTS.cpp

@ -89,6 +89,7 @@ void CommandLine::runCLI(ParserBase *processor)
cout.flush();
std::string inbuf;
getline(cin, inbuf, '\n');
if (!cin.good()) break;
// The parser returns -1 on exit.
if (processor->process(inbuf,cout)<0) break;
#endif // !HAVE_LIBREADLINE ]

@ -67,14 +67,63 @@ static const char* errorCodeText[] = {
extern TransceiverManager gTRX;
CommandLine::Parser CommandLine::gParser;
/**@name Helper functions. */
//@{
void CommandLine::exitBTS(unsigned waitSec, ostream& os)
{
// Block creation of new channels.
gBTS.hold(true);
if (waitSec!=0) {
os << "waiting up to " << waitSec << " seconds for clearing of "
<< gBTS.TCHActive() << " active calls" << endl;
// Wait up to the timeout for active channels to release.
time_t finish = time(NULL) + waitSec;
while (time(NULL)<finish) {
unsigned load = gBTS.SDCCHActive() + gBTS.TCHActive();
if (load==0) break;
sleep(1);
}
}
bool loads = false;
if (gBTS.SDCCHActive()>0) {
LOG(WARN) << "dropping " << gBTS.SDCCHActive() << " control transactions on exit";
loads = true;
}
if (gBTS.TCHActive()>0) {
LOG(WARN) << "dropping " << gBTS.TCHActive() << " calls on exit";
loads = true;
}
if (loads) {
os << endl << "exiting with loads:" << endl;
printStats(os);
}
if (gConfig.defines("Control.TMSITable.SavePath")) {
gTMSITable.save(gConfig.getStr("Control.TMSITable.SavePath"));
}
os << endl << "exiting..." << endl;
}
void CommandLine::printStats(ostream& os)
{
os << "SDCCH load: " << gBTS.SDCCHActive() << '/' << gBTS.SDCCHTotal() << endl;
os << "TCH/F load: " << gBTS.TCHActive() << '/' << gBTS.TCHTotal() << endl;
os << "AGCH/PCH load: " << gBTS.AGCHLoad() << ',' << gBTS.PCHLoad() << endl;
// paging table size
os << "Paging table size: " << gBTS.pager().pagingEntryListSize() << endl;
os << "Transactions/TMSIs: " << gTransactionTable.size() << ',' << gTMSITable.size() << endl;
// 3122 timer current value (the number of seconds an MS should hold off the next RACH)
os << "T3122: " << gBTS.T3122() << " ms" << endl;
}
//@}
/**@name Commands for the CLI. */
//@{
// forward refs
int printStats(int argc, char** argv, ostream& os);
/*
A CLI command takes the argument in an array.
It returns 0 on success.
@ -146,8 +195,6 @@ int showHelp(int argc, char** argv, ostream& os)
return SUCCESS;
}
/** A function to return -1, the exit code for the caller. */
int exit_function(int argc, char** argv, ostream& os)
{
@ -155,36 +202,8 @@ int exit_function(int argc, char** argv, ostream& os)
if (argc>2) return BAD_NUM_ARGS;
if (argc==2) wait = atoi(argv[1]);
if (wait!=0)
os << "waiting up to " << wait << " seconds for clearing of "
<< gBTS.TCHActive() << " active calls" << endl;
exitBTS(wait, os);
// Block creation of new channels.
gBTS.hold(true);
// Wait up to the timeout for active channels to release.
time_t finish = time(NULL) + wait;
while (time(NULL)<finish) {
unsigned load = gBTS.SDCCHActive() + gBTS.TCHActive();
if (load==0) break;
sleep(1);
}
bool loads = false;
if (gBTS.SDCCHActive()>0) {
LOG(WARN) << "dropping " << gBTS.SDCCHActive() << " control transactions on exit";
loads = true;
}
if (gBTS.TCHActive()>0) {
LOG(WARN) << "dropping " << gBTS.TCHActive() << " calls on exit";
loads = true;
}
if (loads) {
os << endl << "exiting with loads:" << endl;
printStats(1,NULL,os);
}
if (gConfig.defines("Control.TMSITable.SavePath")) {
gTMSITable.save(gConfig.getStr("Control.TMSITable.SavePath"));
}
os << endl << "exiting..." << endl;
return -1;
}
@ -327,17 +346,10 @@ int sendrrlp(int argc, char** argv, ostream& os)
/** Print current usage loads. */
int printStats(int argc, char** argv, ostream& os)
int cliPrintStats(int argc, char** argv, ostream& os)
{
if (argc!=1) return BAD_NUM_ARGS;
os << "SDCCH load: " << gBTS.SDCCHActive() << '/' << gBTS.SDCCHTotal() << endl;
os << "TCH/F load: " << gBTS.TCHActive() << '/' << gBTS.TCHTotal() << endl;
os << "AGCH/PCH load: " << gBTS.AGCHLoad() << ',' << gBTS.PCHLoad() << endl;
// paging table size
os << "Paging table size: " << gBTS.pager().pagingEntryListSize() << endl;
os << "Transactions/TMSIs: " << gTransactionTable.size() << ',' << gTMSITable.size() << endl;
// 3122 timer current value (the number of seconds an MS should hold off the next RACH)
os << "T3122: " << gBTS.T3122() << " ms" << endl;
printStats(os);
return SUCCESS;
}
@ -813,7 +825,7 @@ Parser::Parser()
addCommand("findimsi", findimsi, "[IMSIPrefix] -- prints all imsi's that are prefixed by IMSIPrefix");
addCommand("sendsms", sendsms, "<IMSI> <src> <text> -- send SMS to <IMSI>, addressed from <src>.");
addCommand("sendrrlp", sendrrlp, "<IMSI> <hexstring> -- send RRLP message <hexstring> to <IMSI>.");
addCommand("load", printStats, "-- print the current activity loads.");
addCommand("load", cliPrintStats, "-- print the current activity loads.");
addCommand("cellid", cellID, "[MCC MNC LAC CI] -- get/set location area identity (MCC, MNC, LAC) and cell ID (CI)");
addCommand("calls", calls, "-- print the transaction table");
addCommand("config", config, "[] OR [patt] OR [key val(s)] -- print the current configuration, print configuration values matching a pattern, or set/change a configuration value");

@ -79,6 +79,13 @@ protected:
extern CommandLine::Parser gParser;
/** Exit BTS, waiting up to waitSec seconds for active channels to release. */
void exitBTS(unsigned waitSec, std::ostream& os);
/** Print current usage loads. */
void printStats(std::ostream& os);
} // CLI

@ -69,7 +69,8 @@ GSMConfig gBTS;
// Our interface to the software-defined radio.
TransceiverManager gTRX(1, gConfig.getStr("TRX.IP"), gConfig.getNum("TRX.Port"));
/// Pointer to the server socket if we run remote CLI.
ConnectionServerSocket *gCLIServerSock = NULL;
@ -251,18 +252,63 @@ void startBTS()
void stopBTS()
{
if (gConfig.defines("Control.TMSISavePath")) {
gTMSITable.save(gConfig.getStr("Control.TMSISavePath"));
if (!gBTS.hold()) {
exitBTS(0, cout);
}
if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
}
void exitCLI()
{
if (gCLIServerSock != NULL) {
// Closing server sock
gCLIServerSock->close();
gCLIServerSock = NULL;
}
// Closing server standard input to shutdown local CLI
cin.setstate(ios::eofbit);
// cin.putback('\n');
fclose(stdin);
}
void signalHandler(int sig)
{
COUT("Handling signal " << sig);
switch(sig){
case SIGHUP:
// re-read the config
// TODO::
break;
case SIGTERM:
case SIGINT:
// finalize the server
exitCLI();
break;
default:
break;
}
}
int main(int argc, char *argv[])
{
srandom(time(NULL));
// Signal to re-read config
if (signal(SIGHUP, signalHandler) == SIG_ERR) {
CERR("Error while setting handler for SIGHUP.");
}
// Signal to shutdown gracefully
if (signal(SIGTERM, signalHandler) == SIG_ERR) {
CERR("Error while setting handler for SIGTERM.");
}
// Ctrl-C signal
if (signal(SIGINT, signalHandler) == SIG_ERR) {
CERR("Error while setting handler for SIGINT.");
}
COUT("\n\n" << gOpenBTSWelcome << "\n");
if (gConfig.defines("Log.FileName")) {
@ -274,10 +320,14 @@ int main(int argc, char *argv[])
if (strcasecmp(gConfig.getStr("CLI.Type"),"TCP") == 0) {
ConnectionServerSocketTCP serverSock(gConfig.getNum("CLI.TCP.Port"),
gConfig.getStr("CLI.TCP.IP"));
gCLIServerSock = &serverSock;
runCLIServer(&serverSock);
gCLIServerSock = NULL;
} else if (strcasecmp(gConfig.getStr("CLI.Type"),"Unix") == 0) {
ConnectionServerSocketUnix serverSock(gConfig.getStr("CLI.Unix.Path"));
gCLIServerSock = &serverSock;
runCLIServer(&serverSock);
gCLIServerSock = NULL;
} else {
runCLI(&gParser);
}