242 lines
7.9 KiB
C++
242 lines
7.9 KiB
C++
#define CD_MAIN
|
|
#include "ausreg-cd.h"
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
bool cdHasTk;
|
|
char cdOrTkValue;
|
|
const char *cdOrTk=&cdOrTkValue;
|
|
|
|
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;
|
|
|
|
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)
|
|
{
|
|
const char *exeName,*banner = "\n" CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__ " (%d)\n";
|
|
int mthParm, rc = OK;
|
|
|
|
thisCliever = NULL;
|
|
|
|
cdHasTk = strstr(argv[0],"loadtk") ? true : false;
|
|
cdOrTkValue = cdHasTk ? 'd' : 'D'; // d == EPP Toolkit enabled, D = !d
|
|
|
|
//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);
|
|
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 < 2 || argc > 7) usage();
|
|
|
|
thisConfig->telemetryPort = atoi(argv[1]);
|
|
if (thisConfig->telemetryPort < 1000 || thisConfig->telemetryPort > 65535)
|
|
{
|
|
std::cerr << "The <telemetry-udp-port> value is invalid.\n";
|
|
exit(1);
|
|
}
|
|
thisConfig->telemetryPortStr = std::string(argv[1]);
|
|
for (mthParm=2;mthParm < argc;mthParm++) {
|
|
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> is required, 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);
|
|
}
|