DRDE/APIG/client/ausreg-cd.cpp

253 lines
8.0 KiB
C++

#define CD_MAIN
#include "ausreg-cd.h"
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
bool cdHasTk;
const char *cdOrTk=NULL;
using namespace std;
/*
* This is the shell for the Unix Client Server (Cliever) daemon.
* In this design, this "cliever" is more client than server and
* the main arch has the md as the thing the secondary name provder
* is using to talk to primary providers.
*
* It also contains a CLI for sending commands used in OTE testing
* to verify the EPP directives. This ruby swig binding of this
* is behind the final OTE test harness.
*
*/
void runCommander();
void setSignals();
void signal_handler(int);
void usage();
using namespace boost::interprocess;
using namespace std;
//RAII constructor/destructor
struct shm_remove
{
shm_remove() { shared_memory_object::remove("ausreg-cd-global"); }
~shm_remove() { shared_memory_object::remove("ausreg-cd-global"); }
} remover;
shared_memory_object shm(create_only, "ausreg-cd-global", read_write);
void acClientServer() { // AKA "Cliever"
int i,lfp;
char str[10];
thisConfig->daemonProcess = fork();
if (thisConfig->daemonProcess < 0) {
puts("Can't initialize process!");
exit(1);
}
if (thisConfig->runCommander && getpid() == thisConfig->shellProcess)
{setSignals(); runCommander();}
setsid(); /* obtain a new process group */
i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standard I/O */
umask(027); /* set newly created file permissions */
chdir(RUNNING_DIR); /* change running directory */
lfp=open(CD_LOCK_FILE,O_RDWR|O_CREAT,0640);
if (lfp<0) {puts("Can't open lockfile!"); exit(1);}
if (lockf(lfp,F_TLOCK,0)<0)
{puts("Can't lock lockfile!"); exit(0);}
shared_memory_object shm(open_only, "ausreg-cd-global", read_write);
mapped_region acCDglobal(shm, read_write);
gm = (ac_cd_global *)acCDglobal.get_address();
if (strcmp(gm->id,"ausreg-cd")) // Same deal
{theseLogs.logN(0,"Daemon couldn't identify global memory. Bye."); exit(1);}
gm->daemon_pid = getpid();
sprintf(str,"%d",getpid());
theseLogs.logN(1,"ausreg-cd running (%s)",str);
strcat(str,"\n");
write(lfp,str,strlen(str)); /* record pid to lockfile */
setSignals();
theseLogs.init("ausreg-cd");
theseLogs.logN(0,CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__);
theseLogs.logN(3,"Cliever processing(%d) begins for devices on port %s to MD at %s.",getpid(),thisConfig->telemetryPortStr.c_str(),thisConfig->mdAddress.c_str());
try {
boost::thread cliever(runCliever);
boost::thread apiLayer(runAPILayer);
#ifdef XMLRPC_C
xmlrpc_c::serverAbyss myAbyssServer(
thisConfig->api_registry,
thisConfig->xmlrpcPort,
thisConfig->xmlrpcLogpath
);
#endif
if (!apiLayer.joinable() || !cliever.joinable()) {
if (!apiLayer.joinable())
theseLogs.logN(0,"Failed to start API layer, ausred-cd process will terminate.");
if (!cliever.joinable())
theseLogs.logN(0,"Failed to start client-server, ausureg-cd process will terminate.");
}
else {
theseLogs.logN(0,"Cliever started OK.");
#ifdef XMLRPC_C
theseLogs->logN(2,"%s %d","Accepting XMLRPC API Requests on Port",thisConfig->xmlrpcPort);
myAbyssServer.run();
#endif
apiLayer.join();
theseLogs.logN(0,"ausreg-cd EOJ.");
}
}
catch (std::exception &e)
{
theseLogs.logN(1,"Exception: %s",e.what());
}
catch (...) {
theseLogs.logN(0,"General fault.");
}
exit(thisCliever->rc);
}
int main(int const argc, const char ** const argv)
{
bool noParms=false;
const char *exeName,*banner = "\n" CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__ " (%d)\n";
int mthParm=2, rc = OK;
thisCliever = NULL;
cdOrTk = argv[0];
cdHasTk = strstr(cdOrTk,"ausreg-cd") ? true : false;
shm.truncate(CD_GLOBAL_SIZE);
mapped_region acCDglobal(shm, read_write);
memset(acCDglobal.get_address(), 0, acCDglobal.get_size());
gm = (ac_cd_global *)acCDglobal.get_address();
strcpy(gm->id,"ausreg-cd");
strcmp(gm->id,"ausreg-cd"); // Will segfault if there is a problem so catches are futile.
// But the signal trap will catch the fault.
thisConfig = new clientDaemonConfig();
thisConfig->shellProcess = getpid();
strcpy(thisConfig->origCmd,argv[0]);
if (argc < 1 || argc > 7) usage();
if (argc == 1 || *argv[1] == '?')
{ noParms = true;
thisConfig->telemetryPort = 5000;
mthParm=1;
}
else thisConfig->telemetryPort = atoi(argv[1]);
if (thisConfig->telemetryPort < 1000 || thisConfig->telemetryPort > 65535)
{
std::cerr << "The <telemetry-udp-port> value is invalid.\n";
exit(1);
}
if (argc > 1) thisConfig->telemetryPortStr = std::string(argv[1]);
for (;mthParm < argc;mthParm++) {
if (*argv[mthParm] == '?') {
usage();
}
else
if (*argv[mthParm] == '*') {
thisConfig->runCommander = false;
}
else
if (!strncmp(argv[mthParm],"device=",7)) {
thisConfig->deviceName = std::string(argv[mthParm]+8);
}
else
if (!strncmp(argv[mthParm],"logs=",4)) {
strcpy(thisConfig->logPath,argv[mthParm]+5);
}
else
if (!strncmp(argv[mthParm],"mdIP=",4)) {
thisConfig->mdAddress = std::string(argv[mthParm]+5);
}
else usage();
}
if (thisConfig->runCommander) printf(banner,thisConfig->shellProcess);
acClientServer();
while(!gm->graceful) sleep(2);
}
void runCommander() {
char msg[128];
int i;
mdCommander commander;
theseLogs.init("ausreg-cd-ui");
theseLogs.logN(0,"Interactive command processor started.");
commander.driver();
if (thisConfig->terminateRequest) {
theseLogs.logN(0,"Interactive shutdown requested.");
puts("ausreg-cd operator issued terminate command.");
kill(gm->daemon_pid,SIGTERM);
} else {
theseLogs.logN(0,"Interactive command processor ended.");
sprintf(msg,"Commander terminated, ausreg-cd continues (%d).",gm->daemon_pid);
puts(msg);
}
theseLogs.logN(1,"Closing out I/O for shell process (%d)",thisConfig->shellProcess);
for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
exit(0);
}
void setSignals() {
signal(SIGCHLD,SIG_IGN); /* ignore child */
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN); // both input
signal(SIGTTIN,SIG_IGN); // and output
signal(SIGSEGV,signal_handler);
signal(SIGUSR1,signal_handler); // commander log messages
signal(SIGHUP,signal_handler); /* catch hangup signal */
signal(SIGTERM,signal_handler); /* catch kill signal */
}
void signal_handler(int sig)
{ int debug=0;
switch(sig) {
case SIGSEGV:
debug=1; // for breakpoint
theseLogs.logN(0,"Segfault great that you can see this.");
break;
case SIGUSR1:
break;
case SIGHUP:
theseLogs.logN(0,"hangup signal caught, currently ausreg-cd ignores this.");
break;
case SIGTERM:
theseLogs.logN(0,"terminate signal caught, ausreg-cd will shutdown.");
cdShutdown termEvent;
termEvent.send();
break;
}
}
void usage() {
std::cerr << "Usage: " << cdOrTk << " <udp-port> ['*'] [device=TEST] [mdIP=" MD_DEFAULT_IP "] [logs=\\tmp]\n\n where \n\n"
"\t <udp-port> defaults to 5000, must be the first parameter, and must be 1000 or greater. \n"
"\t The other parameters are optional and non-positional and take the shown defaults. \n"
"\t '*', if present, indicates skip the command loop (string quotes may be required). \n\n";
exit(1);
}