Catch SIGINT, SIGTERM and SIGHUP and shutdown the server gracefully.
This commit is contained in:
parent
163290b60e
commit
8598e72800
|
@ -89,6 +89,7 @@ void CommandLine::runCLI(ParserBase *processor)
|
||||||
cout.flush();
|
cout.flush();
|
||||||
std::string inbuf;
|
std::string inbuf;
|
||||||
getline(cin, inbuf, '\n');
|
getline(cin, inbuf, '\n');
|
||||||
|
if (!cin.good()) break;
|
||||||
// The parser returns -1 on exit.
|
// The parser returns -1 on exit.
|
||||||
if (processor->process(inbuf,cout)<0) break;
|
if (processor->process(inbuf,cout)<0) break;
|
||||||
#endif // !HAVE_LIBREADLINE ]
|
#endif // !HAVE_LIBREADLINE ]
|
||||||
|
|
|
@ -67,14 +67,63 @@ static const char* errorCodeText[] = {
|
||||||
extern TransceiverManager gTRX;
|
extern TransceiverManager gTRX;
|
||||||
CommandLine::Parser CommandLine::gParser;
|
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. */
|
/**@name Commands for the CLI. */
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
// forward refs
|
|
||||||
int printStats(int argc, char** argv, ostream& os);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A CLI command takes the argument in an array.
|
A CLI command takes the argument in an array.
|
||||||
It returns 0 on success.
|
It returns 0 on success.
|
||||||
|
@ -146,8 +195,6 @@ int showHelp(int argc, char** argv, ostream& os)
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** A function to return -1, the exit code for the caller. */
|
/** A function to return -1, the exit code for the caller. */
|
||||||
int exit_function(int argc, char** argv, ostream& os)
|
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) return BAD_NUM_ARGS;
|
||||||
if (argc==2) wait = atoi(argv[1]);
|
if (argc==2) wait = atoi(argv[1]);
|
||||||
|
|
||||||
if (wait!=0)
|
exitBTS(wait, os);
|
||||||
os << "waiting up to " << wait << " seconds for clearing of "
|
|
||||||
<< gBTS.TCHActive() << " active calls" << endl;
|
|
||||||
|
|
||||||
// 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,17 +346,10 @@ int sendrrlp(int argc, char** argv, ostream& os)
|
||||||
|
|
||||||
|
|
||||||
/** Print current usage loads. */
|
/** 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;
|
if (argc!=1) return BAD_NUM_ARGS;
|
||||||
os << "SDCCH load: " << gBTS.SDCCHActive() << '/' << gBTS.SDCCHTotal() << endl;
|
printStats(os);
|
||||||
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;
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +825,7 @@ Parser::Parser()
|
||||||
addCommand("findimsi", findimsi, "[IMSIPrefix] -- prints all imsi's that are prefixed by IMSIPrefix");
|
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("sendsms", sendsms, "<IMSI> <src> <text> -- send SMS to <IMSI>, addressed from <src>.");
|
||||||
addCommand("sendrrlp", sendrrlp, "<IMSI> <hexstring> -- send RRLP message <hexstring> to <IMSI>.");
|
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("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("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");
|
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;
|
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
|
} // CLI
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,8 @@ GSMConfig gBTS;
|
||||||
// Our interface to the software-defined radio.
|
// Our interface to the software-defined radio.
|
||||||
TransceiverManager gTRX(1, gConfig.getStr("TRX.IP"), gConfig.getNum("TRX.Port"));
|
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()
|
void stopBTS()
|
||||||
{
|
{
|
||||||
if (gConfig.defines("Control.TMSISavePath")) {
|
if (!gBTS.hold()) {
|
||||||
gTMSITable.save(gConfig.getStr("Control.TMSISavePath"));
|
exitBTS(0, cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
|
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[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
srandom(time(NULL));
|
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");
|
COUT("\n\n" << gOpenBTSWelcome << "\n");
|
||||||
|
|
||||||
if (gConfig.defines("Log.FileName")) {
|
if (gConfig.defines("Log.FileName")) {
|
||||||
|
@ -274,10 +320,14 @@ int main(int argc, char *argv[])
|
||||||
if (strcasecmp(gConfig.getStr("CLI.Type"),"TCP") == 0) {
|
if (strcasecmp(gConfig.getStr("CLI.Type"),"TCP") == 0) {
|
||||||
ConnectionServerSocketTCP serverSock(gConfig.getNum("CLI.TCP.Port"),
|
ConnectionServerSocketTCP serverSock(gConfig.getNum("CLI.TCP.Port"),
|
||||||
gConfig.getStr("CLI.TCP.IP"));
|
gConfig.getStr("CLI.TCP.IP"));
|
||||||
|
gCLIServerSock = &serverSock;
|
||||||
runCLIServer(&serverSock);
|
runCLIServer(&serverSock);
|
||||||
|
gCLIServerSock = NULL;
|
||||||
} else if (strcasecmp(gConfig.getStr("CLI.Type"),"Unix") == 0) {
|
} else if (strcasecmp(gConfig.getStr("CLI.Type"),"Unix") == 0) {
|
||||||
ConnectionServerSocketUnix serverSock(gConfig.getStr("CLI.Unix.Path"));
|
ConnectionServerSocketUnix serverSock(gConfig.getStr("CLI.Unix.Path"));
|
||||||
|
gCLIServerSock = &serverSock;
|
||||||
runCLIServer(&serverSock);
|
runCLIServer(&serverSock);
|
||||||
|
gCLIServerSock = NULL;
|
||||||
} else {
|
} else {
|
||||||
runCLI(&gParser);
|
runCLI(&gParser);
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue