#define CD_MAIN #include "ausreg-cd.h" #include #include #include #include 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 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 << " ['*'] [device=TEST] [mdIP=" MD_DEFAULT_IP "] [logs=\\tmp]\n\n where \n\n" "\t 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); }