diff --git a/Essentials/pAntler/Antler.cpp b/Essentials/pAntler/Antler.cpp index 8f9b80f..8ccebe8 100644 --- a/Essentials/pAntler/Antler.cpp +++ b/Essentials/pAntler/Antler.cpp @@ -1,4 +1,6 @@ + #include "Antler.h" +#include "MOOSProc.h" using namespace std; #include @@ -11,22 +13,19 @@ using namespace std; -#define DEBUG_LAUNCH 0 CAntler::CAntler() { - - - m_JobLock.UnLock(); + m_JobLock.UnLock(); m_bNewJob = false; m_sAntlerName = "Monarch"; m_sDBHost = "localhost"; m_nDBPort = 9000; m_bQuitCurrentJob = false; - m_eVerbosity=CHATTY; + m_eVerbosity = CHATTY; } //this is the vanilla version of Run - called to run from a single mission file -bool CAntler::Run(const std::string & sMissionFile,std::set Filter ) +bool CAntler::Run(const std::string & sMissionFile, std::set Filter) { m_bHeadless = false; m_sMissionFile = sMissionFile; @@ -35,7 +34,7 @@ bool CAntler::Run(const std::string & sMissionFile,std::set Filter } //this version will wait for a mission fiel to be sent via a DB -bool CAntler::Run(const std::string & sHost, int nPort, const std::string & sAntlerName) +bool CAntler::Run(const std::string & sHost, int nPort, const std::string & sAntlerName) { //this is more interesting... m_sAntlerName = sAntlerName; @@ -44,27 +43,30 @@ bool CAntler::Run(const std::string & sHost, int nPort, const std::string & sAn m_bHeadless = true; - if(!ConfigureMOOSComms()) + if (!ConfigureMOOSComms()) return true; - MOOSTrace(" This is headless Antler called \"%s\"\n Waiting for mission file from %s:%d\n",m_sAntlerName.c_str(),m_sDBHost.c_str(),m_nDBPort); + MOOSTrace(" This is headless Antler called \"%s\"\n" + "Waiting for mission file from %s:%d\n", + m_sAntlerName.c_str(), + m_sDBHost.c_str(), + m_nDBPort); - const char * sSpin = "-\\|/"; - while(1) + const char * sSpin = "-\\|/"; + while (1) { //wait to be signalled that there is work to do... int i = 0; - while(!m_bNewJob) + while (!m_bNewJob) { MOOSPause(500); - MOOSTrace(" Speak to me Monarch....%c\r",sSpin[i++%3]); - } - + MOOSTrace(" Speak to me Monarch....%c\r", sSpin[i++%3]); + } //no more launching until this community is complete m_JobLock.Lock(); - Spawn(m_sReceivedMissionFile,true); + Spawn(m_sReceivedMissionFile, true); m_bNewJob = false; m_JobLock.UnLock(); @@ -75,37 +77,52 @@ bool CAntler::Run(const std::string & sHost, int nPort, const std::string & sAn bool CAntler::DoRemoteControl() { - - - - while(1) + while (1) { MOOSPause(100); - if(!m_pMOOSComms->IsConnected()) + if (!m_pMOOSComms->IsConnected()) continue; //better check mail MOOSMSG_LIST NewMail; - if(m_pMOOSComms->Fetch(NewMail)) + if (m_pMOOSComms->Fetch(NewMail)) { CMOOSMsg Msg; - if(m_bHeadless) + if (!m_bHeadless) + { + if (m_pMOOSComms->PeekAndCheckMail(NewMail, "ANTLER_STATUS", Msg)) + { + std::string sWhat; + MOOSValFromString(sWhat, Msg.GetString(), "Action"); + std::string sProc; + MOOSValFromString(sProc, Msg.GetString(), "Process"); + std::string sID; + MOOSValFromString(sID, Msg.GetString(), "AntlerID"); + + MOOSTrace(" [rmt] Process %-15s has %s (by %s)\n", + sProc.c_str(), + sWhat.c_str(), + sID.c_str()); + } + } + else // headless { - if(m_pMOOSComms->PeekMail(NewMail,"MISSION_FILE",Msg)) + if (m_pMOOSComms->PeekMail(NewMail, "MISSION_FILE", Msg)) { MOOSTrace("\n|***** Dynamic Brief *****|\n\n"); //make a new file name - m_sReceivedMissionFile = MOOSFormat("runtime_%s.moos",MOOSGetTimeStampString().c_str()); + m_sReceivedMissionFile = MOOSFormat("runtime_%s.moos", + MOOSGetTimeStampString().c_str()); - MOOSTrace(" %s received [%d bytes]\n",m_sReceivedMissionFile.c_str(),Msg.GetString().size()); + MOOSTrace(" %s received [%d bytes]\n", + m_sReceivedMissionFile.c_str(), + Msg.GetString().size()); MOOSTrace(" shutting down all current spawned processes:\n"); - //tell the current job to quit + //tell the current job to quit, and wait for it to happen m_bQuitCurrentJob = true; - - //wait for that to happen m_JobLock.Lock(); //here we copy the mission file contained in the message to @@ -114,107 +131,79 @@ bool CAntler::DoRemoteControl() //suck out the Antler filter line std::string sFilter; std::getline(ss, sFilter); - MOOSTrace("%s\n", sFilter.c_str()); - MOOSChomp(sFilter,"ANTLERFILTER:", true); + MOOSTrace("%s\n", sFilter.c_str()); + MOOSChomp(sFilter, "ANTLERFILTER:", true); std::stringstream ssF(sFilter); //fill in the filter set std::copy(istream_iterator(ssF), istream_iterator(), - std::inserter(m_Filter,m_Filter.begin())); - + std::inserter(m_Filter, m_Filter.begin())); //write out the whole file std::ofstream Out(m_sReceivedMissionFile.c_str()); - if(!Out.is_open()) + if (!Out.is_open()) { m_JobLock.UnLock(); return MOOSFail("failed to open mission file for writing"); } - //you've gotta lurve C++ ... - Out<PeekAndCheckMail(NewMail, "ANTLER_STATUS", Msg)) - { - std::string sWhat; - MOOSValFromString(sWhat, Msg.GetString(),"Action"); - std::string sProc; - MOOSValFromString(sProc, Msg.GetString(),"Process"); - std::string sID; - MOOSValFromString(sID, Msg.GetString(), "AntlerID"); - - MOOSTrace(" [rmt] Process %-15s has %s (by %s)\n",sProc.c_str(),sWhat.c_str(),sID.c_str()); - } - } - } } } + bool CAntler::SetVerbosity(VERBOSITY_LEVEL eLevel) { - m_eVerbosity = eLevel; - switch(eLevel) - { - case CHATTY: - break; - case TERSE: - InhibitMOOSTraceInThisThread(true); - break; - case QUIET: - InhibitMOOSTraceInThisThread(true); - if(m_pMOOSComms!=NULL) - m_pMOOSComms->SetQuiet(true); - - } - return true; + m_eVerbosity = eLevel; + switch(eLevel) + { + case CHATTY: + break; + case TERSE: + InhibitMOOSTraceInThisThread(true); + break; + case QUIET: + InhibitMOOSTraceInThisThread(true); + if (m_pMOOSComms != NULL) + m_pMOOSComms->SetQuiet(true); + } + return true; } + bool CAntler::ConfigureMOOSComms() { - - //start a monitoring thread m_RemoteControlThread.Initialise(_RemoteControlCB, this); m_RemoteControlThread.Start(); - m_pMOOSComms = new CMOOSCommClient; - m_pMOOSComms->SetOnConnectCallBack(_MOOSConnectCB,this); - m_pMOOSComms->SetOnDisconnectCallBack(_MOOSDisconnectCB,this); + m_pMOOSComms->SetOnConnectCallBack(_MOOSConnectCB, this); + m_pMOOSComms->SetOnDisconnectCallBack(_MOOSDisconnectCB, this); m_pMOOSComms->SetQuiet(true); - std::string sMe =MOOSFormat("Antler{%s}",m_sAntlerName.c_str()); + std::string sMe = MOOSFormat("Antler{%s}", m_sAntlerName.c_str()); //try and connect to a DB - if(!m_pMOOSComms->Run(m_sDBHost.c_str(), (long int)m_nDBPort, sMe.c_str(), 1)) + if (!m_pMOOSComms->Run(m_sDBHost.c_str(), (long int)m_nDBPort, sMe.c_str(), 1)) return MOOSFail("could not set up MOOSComms\n"); - return true; } -bool CAntler::SendMissionFile( ) +bool CAntler::SendMissionFile() { MOOSTrace("\n\n|***** Propagate *****|\n\n"); CMOOSFileReader FR; @@ -223,44 +212,50 @@ bool CAntler::SendMissionFile( ) //copy the filters in ss<<"ANTLERFILTER:"; - std::copy (m_Filter.begin(), m_Filter.end(), ostream_iterator (ss, " ")); + std::copy (m_Filter.begin(), + m_Filter.end(), + ostream_iterator (ss, " ")); ss<Notify("MISSION_FILE",ss.str()); + m_pMOOSComms->Notify("MISSION_FILE", ss.str()); - MOOSTrace(" Monarch published thinned mission file [%d bytes]\n\n",ss.str().size()); + MOOSTrace(" Monarch published thinned mission file [%d bytes]\n\n", + ss.str().size()); return true; } + + bool CAntler::OnMOOSConnect() { - if(m_bHeadless) + if (m_bHeadless) { MOOSTrace(" Connecting to a DB\n"); - m_pMOOSComms->Register("MISSION_FILE",0); + m_pMOOSComms->Register("MISSION_FILE", 0); } else { - m_pMOOSComms->Register("ANTLER_STATUS",0); + m_pMOOSComms->Register("ANTLER_STATUS", 0); SendMissionFile(); } return true; } + + bool CAntler::OnMOOSDisconnect() { - if(m_bHeadless) + if (m_bHeadless) { - MOOSTrace(" DB Connection Lost\n"); - if(m_bKillOnDBDisconnect) + if (m_bKillOnDBDisconnect) { //look likes the monarch is dead..... MOOSTrace(" shutting down all current spawned processes:\n"); @@ -277,92 +272,40 @@ bool CAntler::OnMOOSDisconnect() return true; } + bool CAntler::PublishProcessQuit(const std::string & sProc) { - if(!m_bHeadless) + if (!m_bHeadless) return false; - if(!m_pMOOSComms->IsConnected()) + if (!m_pMOOSComms->IsConnected()) return false; - m_pMOOSComms->Notify("ANTLER_STATUS",MOOSFormat("Action=Quit,Process=%s,AntlerID=%s",sProc.c_str(),m_sAntlerName.c_str())); - + m_pMOOSComms->Notify("ANTLER_STATUS", + MOOSFormat("Action=Quit,Process=%s,AntlerID=%s", + sProc.c_str(), + m_sAntlerName.c_str())); return true; } + bool CAntler::PublishProcessLaunch(const std::string & sProc) { - if(!m_bHeadless) + if (!m_bHeadless) return false; - if(!m_pMOOSComms->IsConnected()) + if (!m_pMOOSComms->IsConnected()) return false; - m_pMOOSComms->Notify("ANTLER_STATUS",MOOSFormat("Action=Launched,Process=%s,AntlerID=%s",sProc.c_str(),m_sAntlerName.c_str())); + m_pMOOSComms->Notify("ANTLER_STATUS", + MOOSFormat("Action=Launched,Process=%s,AntlerID=%s", + sProc.c_str(), m_sAntlerName.c_str())); return true; } -bool CAntler::KillNicely(MOOSProc* pProc) -{ -#ifndef _WIN32 - - if(m_bSupportGentleKill) - { - if(pProc->m_bNewConsole) - { - //we need to be crafty.... - std::string sCmd = "ps -e -o ppid= -o pid="; - - FILE* In = popen(sCmd.c_str(),"r"); - - if(In!=NULL) - { - bool bFound = false; - char Line[256]; - while(fgets(Line,sizeof(Line),In)) - { - std::stringstream L(Line); - int ppid,pid; - L>>ppid; - L>>pid; - - if(pProc->m_ChildPID==ppid) - { - kill(pid,SIGTERM); - bFound = true; - } - } - pclose(In); - return bFound; - } - else - { - return false; - } - } - else - { - //the proc ID we have is of the actuall MOOSProcess and not its parent - //we can just kill it... - kill(pProc->m_ChildPID,SIGTERM); - } - } - else - { - kill(pProc->m_ChildPID,SIGTERM); - } -#else - //MOOSTrace("Warning - gentle killing of win32 processes is not implemented\n"); - pProc->pWin32Proc->vTerminate(); - return true; - -#endif - return true; -} - bool CAntler::Spawn(const std::string & sMissionFile, bool bHeadless) { @@ -372,15 +315,16 @@ bool CAntler::Spawn(const std::string & sMissionFile, bool bHeadless) //set up the mission file reader - if(!m_MissionReader.SetFile(sMissionFile)) + if (!m_MissionReader.SetFile(sMissionFile)) return MOOSFail("error reading mission file\n"); - m_MissionReader.SetAppName("ANTLER"); //NB no point in running under another name...(I guess Anter1 could launch Antler2 though...) + m_MissionReader.SetAppName("ANTLER"); //NB no point in running under another name... + // (I guess Antler1 could launch Antler2 though...) STRING_LIST sParams; - if(!m_MissionReader.GetConfiguration( m_MissionReader.GetAppName(),sParams)) + if (!m_MissionReader.GetConfiguration(m_MissionReader.GetAppName(), sParams)) return MOOSFail("error reading antler config block from mission file\n"); @@ -388,72 +332,66 @@ bool CAntler::Spawn(const std::string & sMissionFile, bool bHeadless) STRING_LIST::iterator p; sParams.reverse(); - int nTimeMSBetweenSpawn=DEFAULTTIMEBETWEENSPAWN; - m_MissionReader.GetConfigurationParam("MSBetweenLaunches",nTimeMSBetweenSpawn); + int nTimeMSBetweenSpawn = DEFAULTTIMEBETWEENSPAWN; + m_MissionReader.GetConfigurationParam("MSBetweenLaunches", nTimeMSBetweenSpawn); //here we'll figure out a what paths to use when looking for executables m_sDefaultExecutablePath = "SYSTEMPATH"; - m_MissionReader.GetConfigurationParam("ExecutablePath",m_sDefaultExecutablePath); + m_MissionReader.GetConfigurationParam("ExecutablePath", m_sDefaultExecutablePath); - if(!MOOSStrCmp("SYSTEMPATH",m_sDefaultExecutablePath)) + if (MOOSStrCmp("SYSTEMPATH", m_sDefaultExecutablePath)) + { + MOOSTrace("Unless directed otherwise using system path to locate binaries \n"); + m_sDefaultExecutablePath = ""; + } + else { - //MOOSTrace("\"ExecutablePath\" is %s\n",m_sDefaultExecutablePath.c_str()); - if(*m_sDefaultExecutablePath.rbegin()!='/') + //MOOSTrace("\"ExecutablePath\" is %s\n", m_sDefaultExecutablePath.c_str()); + if (*m_sDefaultExecutablePath.rbegin() != '/') { //look to add extra / if needed - m_sDefaultExecutablePath+='/'; + m_sDefaultExecutablePath += '/'; } - } - else - { - MOOSTrace("Unless directed otherwise using system path to locate binaries \n"); - m_sDefaultExecutablePath=""; } - - //are we being ask to support gentle process killing? -#ifdef _WIN32 - m_bSupportGentleKill= false; -#else - m_bSupportGentleKill = true; - m_MissionReader.GetConfigurationParam("GentleKill",m_bSupportGentleKill); -#endif - - - - //no cycle through each line in the configuration block. If it begins with run then it means launch - for(p = sParams.begin();p!=sParams.end();p++) + //are we being ask to support gentle process killing? + m_MissionReader.GetConfigurationParam("GentleKill", m_bSupportGentleKill); + + + //now cycle through each line in the configuration block. + // If it begins with run then it means launch + for (p = sParams.begin(); p != sParams.end(); p++) { std::string sLine = *p; - std::string sWhat = MOOSChomp(sLine,"="); + std::string sWhat = MOOSChomp(sLine, "="); - if(MOOSStrCmp(sWhat,"RUN")) + if (MOOSStrCmp(sWhat, "RUN")) { //OK we are being asked to run a process //try to create a process - MOOSProc* pNew = CreateMOOSProcess(sLine); + CMOOSProc* pNew = CreateMOOSProcess(sLine); - if(pNew!=NULL) + if (pNew != NULL) { - //this a really important bit of text most folk will want to see it... - InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET); - { - MOOSTrace(" [%.3d] Process: %-15s ~ %-15s launched successfully\n", - m_nCurrentLaunch, - pNew->m_sApp.c_str(), - pNew->m_sMOOSName.c_str()); - } - InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY); - + //this a really important bit of text most folk will want to see it... + InhibitMOOSTraceInThisThread(m_eVerbosity == QUIET); + { + MOOSTrace(" [%.3d] Process: %-15s ~ %-15s launched successfully\n", + m_nCurrentLaunch, + pNew->GetAppName().c_str(), + pNew->GetMOOSName().c_str()); + } + InhibitMOOSTraceInThisThread(m_eVerbosity != CHATTY); + m_ProcList.push_front(pNew); - m_nCurrentLaunch++; - PublishProcessLaunch(pNew->m_sApp); + m_nCurrentLaunch++; + PublishProcessLaunch(pNew->GetAppName()); } - //wait a while + //wait a while MOOSPause(nTimeMSBetweenSpawn); } @@ -461,581 +399,262 @@ bool CAntler::Spawn(const std::string & sMissionFile, bool bHeadless) - if(bHeadless==false) + if (bHeadless) { - bool bMaster=false; - m_MissionReader.GetConfigurationParam("EnableDistributed",bMaster); - if(bMaster) + m_bKillOnDBDisconnect = true; + m_MissionReader.GetConfigurationParam("KillOnDBDisconnect", m_bKillOnDBDisconnect); + } + else + { + bool bMaster = false; + m_MissionReader.GetConfigurationParam("EnableDistributed", bMaster); + if (bMaster) { - m_MissionReader.GetValue("ServerHost",m_sDBHost); - m_MissionReader.GetValue("ServerPort",m_nDBPort); + m_MissionReader.GetValue("ServerHost", m_sDBHost); + m_MissionReader.GetValue("ServerPort", m_nDBPort); - if(!ConfigureMOOSComms()) + if (!ConfigureMOOSComms()) return MOOSFail("failed to start MOOS comms"); } } - else - { - m_bKillOnDBDisconnect = true; - m_MissionReader.GetConfigurationParam("KillOnDBDisconnect",m_bKillOnDBDisconnect); - } //now wait on all our processes to close.... - while(m_ProcList.size()!=0) + while (m_ProcList.size()) { MOOSPROC_LIST::iterator q; - for(q = m_ProcList.begin();q!=m_ProcList.end();q++) + for (q = m_ProcList.begin(); q != m_ProcList.end(); q++) { - MOOSProc * pMOOSProc = *q; + CMOOSProc* pMOOSProc = *q; -#ifdef _WIN32 - if(m_bQuitCurrentJob) + if (m_bQuitCurrentJob) { - KillNicely(pMOOSProc); + MOOSTrace(" actively killing running child %s\n", + pMOOSProc->GetAppName().c_str()); + pMOOSProc->Stop(m_bSupportGentleKill); } - - - pMOOSProc->pWin32Proc->vWaitForTerminate(100); - if( pMOOSProc->pWin32Proc->dwGetExitCode()!=STILL_ACTIVE) + + if (pMOOSProc->IsStopped()) { - //this a really important bit of text most folk will want to see it... - InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET); - { - MOOSTrace(" [%.3d] Process: %-15s has quit\n", - --m_nCurrentLaunch, - pMOOSProc->m_sApp.c_str()); - } - InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY); + //this a really important bit of text most folk will want to see it... + InhibitMOOSTraceInThisThread(m_eVerbosity == QUIET); + { + MOOSTrace(" [%.3d] Process: %-15s ~ %-15s has quit\n", + --m_nCurrentLaunch, + pMOOSProc->GetAppName().c_str(), + pMOOSProc->GetMOOSName().c_str()); + } + InhibitMOOSTraceInThisThread(m_eVerbosity != CHATTY); - PublishProcessQuit(pMOOSProc->m_sApp); - delete pMOOSProc->pWin32Attrib; - delete pMOOSProc->pWin32Proc; + PublishProcessQuit(pMOOSProc->GetAppName()); delete pMOOSProc; m_ProcList.erase(q); break; } -#else - if(m_bQuitCurrentJob) - { - MOOSTrace(" actively killing running child %s\n",pMOOSProc->m_sApp.c_str()); - KillNicely(pMOOSProc); - //just give it a little time - for pities sake - no need for this pause - MOOSPause(300); - } - - - int nStatus = 0; - if(waitpid(pMOOSProc->m_ChildPID,&nStatus,WNOHANG)>0) - { - - InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET); - { - MOOSTrace(" [%.3d] Process: %-15s has quit\n", - --m_nCurrentLaunch, - pMOOSProc->m_sApp.c_str()); - } - InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY); - - - PublishProcessQuit(pMOOSProc->m_sApp); - - m_ProcList.erase(q); - break; - } + MOOSPause(100); -#endif } } - - return 0; - } -bool CAntler::MakeExtraExecutableParameters(std::string sParam,STRING_LIST & ExtraCommandLineParameters,std::string sProcName,std::string sMOOSName) -{ - - ExtraCommandLineParameters.clear(); - - std::string sExtraParamsName; - if(!MOOSValFromString(sExtraParamsName, sParam, "ExtraProcessParams", true)) - return true;//nothing to do - - std::string sExtraParams; - - //OK look for this configuration string - if(!m_MissionReader.GetConfigurationParam(sExtraParamsName,sExtraParams)) - return MOOSFail(" warning cannot find extra parameters named \"%s\"\n",sExtraParamsName.c_str()); - - while(!sExtraParams.empty()) - ExtraCommandLineParameters.push_back(MOOSChomp(sExtraParams,",")); - - return true; - -} -bool CAntler::MakeConsoleLaunchParams(std::string sParam,STRING_LIST & LaunchList,std::string sProcName,std::string sMOOSName) +CMOOSProc* CAntler::CreateMOOSProcess(string sConfiguration) { - //sParam is a string in the Run=ProcName @ sParam ~ MOOSName - std::string sLaunchConfigurationName; - std::string sLaunchConfiguration; -#ifdef _WIN32 - bool bNIX = false; - -#else - bool bNIX= true; -#endif - + CProcCfg config; - std::string sLaunchKey = bNIX?"XConfig":"Win32Config"; - if(!MOOSValFromString(sLaunchConfigurationName, sParam, sLaunchKey)) + if (!config.ParseConfig(sConfiguration)) { - //some applications are v.important in MOOS if not told otherwise they get special colours - string sBgColor = bNIX? "#DDDDFF" : ""; - string sFgColor = bNIX? "#000000" : ""; - - if(MOOSStrCmp(sProcName,"iRemote")) - { - sBgColor = bNIX ? "#CC0000" : "RED"; - sFgColor = bNIX ? "#FFFFFF" : ""; - } - if(MOOSStrCmp(sProcName,"MOOSDB")) - { - sBgColor = bNIX? "#003300" : "BLUE"; - sFgColor = bNIX? "#FFFFFF" : ""; - } - if(bNIX) - { - sLaunchConfiguration = "-geometry,"+MOOSFormat("80x12+2+%d",(m_nCurrentLaunch++)*50)+ - ",+sb,"+ - ",-fg,"+sFgColor+ - ",-bg,"+sBgColor+ - ",-T,"+MOOSFormat("%s %s",sProcName.c_str(),sMOOSName.empty()?"":MOOSFormat("as MOOSName \"%s\"",sMOOSName.c_str()).c_str()); - } - else - { - sLaunchConfiguration = sBgColor; - } - } - else - { - - //OK look for this configuration string - if(!m_MissionReader.GetConfigurationParam(sLaunchConfigurationName,sLaunchConfiguration)) - return MOOSFail(" warning: could not find resource string called \"%s\"",sLaunchConfigurationName.c_str()) ; - } - - //OK now simply chomp our way through a space delimited list... - while(!sLaunchConfiguration.empty()) - { - MOOSTrimWhiteSpace(sLaunchConfiguration); - std::string sP = MOOSChomp(sLaunchConfiguration,","); - MOOSTrimWhiteSpace(sP); - if(!sP.empty()) - LaunchList.push_back(sP); + return NULL; } - - return !LaunchList.empty(); - - -} + // set pointer to current launch number + config.m_nCurrentLaunch = &m_nCurrentLaunch; + bool bDistributed = false; + m_MissionReader.GetConfigurationParam("EnableDistributed", bDistributed); -CAntler::MOOSProc* CAntler::CreateMOOSProcess(string sConfiguration) -{ - - - //what tis its name? (if no @ symbol we just get the name and no cmdline) - string sProcName = MOOSChomp(sConfiguration,"@"); - - //further parameters are to left left of @ - string sParam = sConfiguration; - - if(sProcName.empty()) + if (!bDistributed) { - MOOSTrace("no process specified - RUN=???\n"); - return NULL; + //we run everything } - - //std::string sFullProcName = m_sDefaultExecutablePath+sProcName; - - //if things go well this will eventually point to a new Process - MOOSProc * pNewProc = NULL; - - //look for tilde demarking end of param=val block - string sOption = MOOSChomp(sParam,"~"); - - - - bool bDistributed=false; - m_MissionReader.GetConfigurationParam("EnableDistributed",bDistributed); - - if(bDistributed) + else { - - - if(m_bHeadless) + std::string sAntlerRequired; + if (!m_bHeadless) + { + //we are a TopMOOS + if (config.GetParamValue("AntlerID", sAntlerRequired)) + return NULL; //this is for a drone + + } + else { //we are a drone - std::string sAntlerRequired; - if(!MOOSValFromString(sAntlerRequired, sOption, "AntlerID", true)) + if (config.GetParamValue("AntlerID", sAntlerRequired)) return NULL; //this is for primary Antler - if(!MOOSStrCmp(sAntlerRequired, m_sAntlerName)) + if (!MOOSStrCmp(sAntlerRequired, m_sAntlerName)) return NULL; //for some other Antler //OK it is for us... //MOOSTrace("Headless Antler found a RUN directive...\n"); } + } + + + //NEW option: launch (process, console, screen) + LAUNCH_TYPE lt = L_UNDEF; + string sLaunchType; + if (config.GetParamValue("LAUNCHTYPE", sLaunchType)) + { + if (MOOSStrCmp("PROCESS", sLaunchType)) + lt = L_PROCESS; + else if (MOOSStrCmp("CONSOLE", sLaunchType)) + lt = L_CONSOLE; + else if (MOOSStrCmp("SCREEN", sLaunchType)) + lt = L_SCREEN; else { - //we are a TopMOOS - std::string sAntlerRequired; - if(MOOSValFromString(sAntlerRequired, sOption, "AntlerID", true)) - return NULL; //this is for a drone - + MOOSTrace("Error: LaunchType was not one of (Process, Console, Screen)\n"); + return NULL; } } - else - { - //we run everything - } - //do we want a new console? + // backwards compatibility with NEWCONSOLE bool bNewConsole = false; - MOOSValFromString(bNewConsole, sOption, "NEWCONSOLE",true); - - //do we want to inhibit the passing of MOOS parameters (mission file and MOOSName) - bool bInhibitMOOSParams = false; - MOOSValFromString(bInhibitMOOSParams, sOption, "InhibitMOOSParams", true); - - //by default process are assumed to be on the system path - //users can specify an alternative path for all process by setting "ExectutablePath=" in the mission file - //configuration block. - //user has the option of specifying paths individually process by process. - //alternativelt they can specify that a particular process shouod be located by system wide and not - //in the default executable path - std::string sSpecifiedPath; - std::string sFullProcName=sProcName; - if(MOOSValFromString(sSpecifiedPath, sOption, "PATH",true)) + bool bGotConsoleParam = MOOSValFromString(bNewConsole, + config.m_sParams, + "NEWCONSOLE", + true); + + // fill in the value if we need it. otherwise, warn if we have both specifiers + if (L_UNDEF == lt) { - if(MOOSStrCmp(sSpecifiedPath,"SYSTEM")) - { - //do nothing - the system should know where to look - } - else - { - //ok we are being told to look in a special place - sFullProcName=sSpecifiedPath+"/"+sProcName; - } + //MOOSTrace("Warning: NEWCONSOLE is deprecated. Use LAUNCHTYPE.\n"); + lt = bNewConsole ? L_CONSOLE : L_PROCESS; } - else + else if (bGotConsoleParam) { - //we just use the Anter-wide Exepath - sFullProcName = m_sDefaultExecutablePath+sProcName; + MOOSTrace("Warning: LAUNCHTYPE overrides NEWCONSOLE, so ignoring this value\n"); } - //name of process as registered...is the first param after "~" - string sMOOSName = MOOSChomp(sParam); - - //here we figure out what MOOS name is implied if none is given (thanks to N.P and F.A) - if(sMOOSName.empty()) - { - std::string sTmp = sProcName; - if(sTmp.rfind('/') != string::npos) - { - sTmp = sTmp.substr(sTmp.rfind('/')+1); - } - if(sTmp.empty()) - { - // ended with a / ? - MOOSTrace("Error in configuration -MOOS Name cannot end in \" / \" : %s\n",sProcName.c_str()); - return NULL; - } - sMOOSName = sTmp; - } - //here we bail according to our filters - if(!m_Filter.empty() && m_Filter.find(sMOOSName)==m_Filter.end()) + if (!m_Filter.empty() && m_Filter.find(config.m_sMOOSName) == m_Filter.end()) { return NULL; } - - //it is pssible to specifiy complicated parameters to the process being launched. (For example - //xterm being passed a whole load of configurations and then the name of the MOOS process it should - //itself launch. This next call fills in a string list of such parameters - STRING_LIST sLaunchParams; - if(bNewConsole) - MakeConsoleLaunchParams(sOption, sLaunchParams,sProcName,sMOOSName); - - - //here we figure what extra command line parameters should be given to the MOOS Process - //being launched. - STRING_LIST ExtraCommandLineParameters; - MakeExtraExecutableParameters(sOption,ExtraCommandLineParameters,sProcName,sMOOSName); - - - - //All good up to here, now make a new process info holder stucture... - pNewProc = new MOOSProc; - pNewProc->m_sApp = sFullProcName; - pNewProc->m_ExtraCommandLineParameters =ExtraCommandLineParameters; - pNewProc->m_ConsoleLaunchParameters = sLaunchParams; - pNewProc->m_bInhibitMOOSParams = bInhibitMOOSParams; - pNewProc->m_sMOOSName = sMOOSName; - pNewProc->m_bNewConsole = bNewConsole; - pNewProc->m_sMissionFile = m_MissionReader.GetFileName(); - - //finally spawn each according to his own -#ifndef _WIN32 - if(DoNixOSLaunch(pNewProc)) -#else - if(DoWin32Launch(pNewProc)) -#endif - { - return pNewProc; - } - else - { - delete pNewProc; - return NULL; - } -} -bool CAntler::ShutDown() -{ - - MOOSPROC_LIST::iterator q; - - MOOSTrace("\n\n|***** Shutdown *****|\n\n"); + //All good up to here, now make a new process holder stucture... + CMOOSProc* pNewProc = NULL; - for(q = m_ProcList.begin();q!=m_ProcList.end();q++) - { - MOOSProc * pMOOSProc = *q; +#ifdef _WIN32 - if(KillNicely(pMOOSProc)) - { - - int nStatus = 0; -#ifndef _WIN32 - - MOOSTrace("\n Signalling %-15s ",pMOOSProc->m_sApp.c_str()); - if(waitpid(pMOOSProc->m_ChildPID,&nStatus,0)>0) - { - MOOSTrace("[OK]"); - } -#endif - } - - } - - MOOSTrace("\n\n All spawned processes shutdown.\n\n That was the MOOS \n\n"); - - - return true; -} + switch (lt) + { + case L_PROCESS: + pNewProc = new CMOOSProcWin32(config, &m_MissionReader); + break; + case L_CONSOLE: + pNewProc = new CMOOSProcConsoleWin32(config, &m_MissionReader); + break; + case L_SCREEN: + MOOSTrace("GNU screen launch is not yet supported under Win32\n"); + return NULL; + default: + MOOSTrace("LAUNCHTYPE and NEWCONSOLE didn't reveal the launch type\n"); + return NULL; + } +#else + switch (lt) + { + case L_PROCESS: + pNewProc = new CMOOSProcNix(config, &m_MissionReader); + break; + case L_CONSOLE: + pNewProc = new CMOOSProcConsoleNix(config, &m_MissionReader); + break; + case L_SCREEN: + pNewProc = new CMOOSProcScreenNix(config, &m_MissionReader); + break; + default: + MOOSTrace("LAUNCHTYPE and NEWCONSOLE didn't reveal the launch type\n"); + return NULL; + } -#ifdef _WIN32 -bool CAntler::DoWin32Launch(CAntler::MOOSProc * pNewProc) -{ - +#endif - try + + if (!pNewProc->BuildConfig()) { - - // make the command line ProcessBinaryName MissionFile ProcessMOOSName - string sCmd = pNewProc->m_sApp+" "; - if(pNewProc->m_bInhibitMOOSParams==false) - sCmd+=pNewProc->m_sMissionFile+" "+pNewProc->m_sMOOSName+" "; - - //continuing this task, here we pass extra parameters to the MOOS process if required - for(STRING_LIST::iterator p = pNewProc->m_ExtraCommandLineParameters.begin();p!=pNewProc->m_ExtraCommandLineParameters.end();p++) - { - sCmd+=*p+" "; - } - - - //make a new process attributes class - pNewProc->pWin32Attrib = NULL; - pNewProc->pWin32Attrib = new XPCProcessAttrib(NULL,(char *)sCmd.c_str()); - - if(pNewProc->m_bNewConsole) - { - pNewProc->pWin32Attrib->vSetCreationFlag(CREATE_NEW_CONSOLE | CREATE_SUSPENDED); - } - else - { - pNewProc->pWin32Attrib->vSetCreationFlag(CREATE_SUSPENDED); - } - - - //we shall use our own start up image as a starting point - STARTUPINFO StartUp; - GetStartupInfo (&StartUp); - - //set up the title - StartUp.lpTitle = (char*)pNewProc->m_sApp.c_str(); - - //set up white text - StartUp.dwFillAttribute = - FOREGROUND_INTENSITY| - FOREGROUND_BLUE | - FOREGROUND_RED | - FOREGROUND_GREEN| - BACKGROUND_INTENSITY ; - - - //give users basic control over backgroun as an RGB combination - for(STRING_LIST::iterator q=pNewProc->m_ConsoleLaunchParameters.begin();q!=pNewProc->m_ConsoleLaunchParameters.end();q++) - { - if(MOOSStrCmp(*q, "BACKGROUND_BLUE")) - { - StartUp.dwFillAttribute|=BACKGROUND_BLUE; - StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE; - } - if(MOOSStrCmp(*q, "BACKGROUND_GREEN")) - { - StartUp.dwFillAttribute|=BACKGROUND_GREEN; - StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE; - } - if(MOOSStrCmp(*q, "BACKGROUND_RED")) - { - StartUp.dwFillAttribute|=BACKGROUND_RED; - StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE; - } - - } - - pNewProc->pWin32Attrib->vSetStartupInfo(&StartUp); - - //no create an object capable of laucnhing win32 processes - pNewProc->pWin32Proc = NULL; - pNewProc->pWin32Proc =new XPCProcess(* pNewProc->pWin32Attrib); - - //go! - pNewProc->pWin32Proc->vResume(); - + MOOSTrace("App %s failed BuildConfig()\n", config.m_sAppName.c_str()); + delete pNewProc; + return NULL; } - catch (XPCException & e) + + + //finally spawn each according to his own + if (pNewProc->Start(m_bSupportGentleKill)) { - if(pNewProc->pWin32Attrib!=NULL) - { - delete pNewProc->pWin32Attrib; - } - if(pNewProc->pWin32Proc!=NULL) - { - delete pNewProc->pWin32Proc; - } - MOOSTrace("*** %s Launch Failed:***\n\a\a",pNewProc->m_sApp.c_str()); - MOOSTrace("%s\n",e.sGetException()); - return false; + return pNewProc; + } + else + { + delete pNewProc; + return NULL; } - - return true; - } -#else -bool CAntler::DoNixOSLaunch(CAntler::MOOSProc * pNewProc) + +bool CAntler::ShutDown() { - - //make a child process - if((pNewProc->m_ChildPID = fork())<0) - { - //hell! - MOOSTrace("fork failed, not good\n"); - return false; - } - else if(pNewProc->m_ChildPID ==0) + + MOOSPROC_LIST::iterator q; + + MOOSTrace("\n\n|***** Shutdown *****|\n\n"); + + for (q = m_ProcList.begin();q != m_ProcList.end(); q++) { - //I'm the child now.. - - STRING_LIST::iterator p = pNewProc->m_ConsoleLaunchParameters.begin(); - unsigned int nExecParams = pNewProc->m_ConsoleLaunchParameters.size()+pNewProc->m_ExtraCommandLineParameters.size()+ 6; - const char ** pExecVParams = new const char* [nExecParams]; - int i = 0; - - //do we need to configure an xterm? - if(pNewProc->m_bNewConsole) + CMOOSProc * pMOOSProc = *q; + + if (pMOOSProc->Stop(m_bSupportGentleKill)) { - pExecVParams[i++] = DEFAULT_NIX_TERMINAL; - if(!pNewProc->m_ConsoleLaunchParameters.empty()) + +#ifndef _WIN32 + + int nStatus = 0; + MOOSTrace("\n Signalling %-15s ~ %-15s", + pMOOSProc->GetAppName().c_str(), + pMOOSProc->GetMOOSName().c_str()); + if (0 < waitpid(pMOOSProc->GetChildPID(), &nStatus, 0)) { - while(p!=pNewProc->m_ConsoleLaunchParameters.end()) - { - pExecVParams[i++] = (p++->c_str()); - } + MOOSTrace("[OK]"); } - - pExecVParams[i++] = "-e"; - - } - - //here we fill in the process name we really care about - pExecVParams[i++] = (pNewProc->m_sApp.c_str()) ; - if(!pNewProc->m_bInhibitMOOSParams) - { - //we do the usual thing of supplying Mission file and MOOSName - pExecVParams[i++] = pNewProc->m_sMissionFile.c_str(); - pExecVParams[i++] = pNewProc->m_sMOOSName.c_str(); - } - - - //here we pass extra parameters to the MOOS process if required - for(p = pNewProc->m_ExtraCommandLineParameters.begin();p!=pNewProc->m_ExtraCommandLineParameters.end();p++) - { - pExecVParams[i++] = (p->c_str()); - } - - //terminate list - pExecVParams[i++] = NULL; -#if(DEBUG_LAUNCH) - for(int j = 0;j (pExecVParams); - if(execvp(pExecVParams[0], pParamList)==-1) - { - MOOSTrace("Failed exec - not good. Called exec as follows:\n"); - exit(EXIT_FAILURE); - } - + } - - //Parent execution stream continues here... - //we need to change the process group of the spawned process so that ctrl-C - //does get sent to all the launched xterms. Instead we will catch ctrl-C ourself - //and find the MOOS process running within the sub process, signal it to die - //so subprocesses can clean up nicely - if(m_bSupportGentleKill) - setpgid(pNewProc->m_ChildPID,0); - - return true; -} -#endif + MOOSTrace("\n\n All spawned processes shutdown.\n\n That was the MOOS \n\n"); + return true; +} diff --git a/Essentials/pAntler/Antler.h b/Essentials/pAntler/Antler.h index 46679fb..a983ff7 100644 --- a/Essentials/pAntler/Antler.h +++ b/Essentials/pAntler/Antler.h @@ -20,152 +20,118 @@ #include #include -#ifdef _WIN32 - #include "XPCProcess.h" - #include "XPCProcessAttrib.h" - #include "XPCException.h" -#else - #include - #include - #include - #include -#endif - -#define DEFAULT_NIX_TERMINAL "xterm" +#include "MOOSProc.h" + #define DEFAULTTIMEBETWEENSPAWN 1000 +using namespace std; class CAntler - { - public: - - //something to hold alient process information for the Antler class - struct MOOSProc - { -#ifdef _WIN32 - XPCProcess * pWin32Proc; - XPCProcessAttrib * pWin32Attrib; -#else - pid_t m_ChildPID; -#endif - std::string m_sApp; - std::string m_sMOOSName; - std::string m_sMissionFile; - bool m_bInhibitMOOSParams; - bool m_bNewConsole; - STRING_LIST m_ExtraCommandLineParameters; - STRING_LIST m_ConsoleLaunchParameters; - - }; - - public: - - //constructor - CAntler(); - //this is the only public function. Call it to have Antler do its thing. - bool Run(const std::string & sMissionFile,std::set Filter = std::set() ); +{ +public: - //run in a headless fashion - instructions will be recieved via MOOSComms - bool Run(const std::string & sHost, int lPort, const std::string & sAntlerName); - - enum VERBOSITY_LEVEL - { - QUIET, - TERSE, - CHATTY, - }; - bool SetVerbosity(VERBOSITY_LEVEL eLevel); - - //call this to cause a clean shut down - bool ShutDown(); - - protected: + //constructor + CAntler(); + //this is the only public function. Call it to have Antler do its thing. + bool Run(const string & sMissionFile, + set Filter = set() ); - //top level spawn - all comes from here - bool Spawn(const std::string & sMissionFile, bool bHeadless = false); - - - //create, configure and launch a process - MOOSProc* CreateMOOSProcess(std:: string sProcName); - - // called to figure out what xterm parameters should be used with launch (ie where should the xterm be and how should it look) - bool MakeConsoleLaunchParams(std::string sParam,STRING_LIST & LaunchList,std::string sProcName,std::string sMOOSName); + //run in a headless fashion - instructions will be recieved via MOOSComms + bool Run(const string & sHost, int lPort, const string & sAntlerName); + + enum VERBOSITY_LEVEL + { + QUIET, + TERSE, + CHATTY, + }; + + enum LAUNCH_TYPE + { + L_UNDEF, + L_PROCESS, + L_CONSOLE, + L_SCREEN // GNU screen, not X11 + }; + + bool SetVerbosity(VERBOSITY_LEVEL eLevel); + + //call this to cause a clean shut down + bool ShutDown(); + +protected: - //caled to figure out what if any additional parameters should be passed to the process being launched - bool MakeExtraExecutableParameters(std::string sParam,STRING_LIST & ExtraCommandLineParameters,std::string sProcName,std::string sMOOSName); + //top level spawn - all comes from here + bool Spawn(const string & sMissionFile, bool bHeadless = false); - //Functions responsible for actually start new processes according to OS -#ifndef _WIN32 - bool DoNixOSLaunch(MOOSProc * pNewProc); -#else - bool DoWin32Launch(MOOSProc *pNewProc); -#endif - bool ConfigureMOOSComms(); - bool SendMissionFile(); - //tell a Monarch what is goinon remotely - bool PublishProcessQuit(const std::string & sProc); - bool PublishProcessLaunch(const std::string & sProc); + //create, configure and launch a process + CMOOSProc* CreateMOOSProcess( string sProcName); - typedef std::list MOOSPROC_LIST; - MOOSPROC_LIST m_ProcList; - std::string m_sDefaultExecutablePath; - CProcessConfigReader m_MissionReader; + + bool ConfigureMOOSComms(); + bool SendMissionFile(); - //if this set is non empty then only procs listed here will be run.. - std::set m_Filter; + //tell a Monarch what is goinon remotely + bool PublishProcessQuit(const string & sProc); + bool PublishProcessLaunch(const string & sProc); - int m_nCurrentLaunch; + typedef list MOOSPROC_LIST; + MOOSPROC_LIST m_ProcList; + string m_sDefaultExecutablePath; + CProcessConfigReader m_MissionReader; - //this is used to communicate with the BD and ultimately other instantiations of - //pAntler on different machines... - CMOOSThread m_RemoteControlThread; - CMOOSCommClient * m_pMOOSComms; - /**method to allow Listen thread to be launched with a MOOSThread.*/ - static bool _RemoteControlCB(void* pParam) - { - CAntler* pMe = (CAntler*) pParam; - return pMe->DoRemoteControl(); - } - /** internal MOOS client callbacks*/ - static bool _MOOSConnectCB(void *pParam) - { - CAntler* pMe = (CAntler*) pParam; - return pMe->OnMOOSConnect(); - } - static bool _MOOSDisconnectCB(void *pParam) - { - CAntler* pMe = (CAntler*) pParam; - return pMe->OnMOOSDisconnect(); - } - /** main comms handling thread*/ - bool DoRemoteControl(); - /** hellos MOOSDB!*/ - bool OnMOOSConnect(); - /** goodby MOOSDB*/ - bool OnMOOSDisconnect(); - - /** Kill a process gently */ - bool KillNicely(MOOSProc* pProc); + //if this set is non empty then only procs listed here will be run.. + set m_Filter; - CMOOSLock m_JobLock; - std::string m_sMissionFile; - bool m_bHeadless; - bool m_bQuitCurrentJob; - bool m_bSupportGentleKill; - bool m_bRunning; - bool m_bNewJob; - std::string m_sMonarchAntler; - bool m_bKillOnDBDisconnect; - std::string m_sReceivedMissionFile; - std::string m_sAntlerName; - std::string m_sDBHost; - int m_nDBPort; + int m_nCurrentLaunch; - VERBOSITY_LEVEL m_eVerbosity; + //this is used to communicate with the BD and ultimately other instantiations of + //pAntler on different machines... + CMOOSThread m_RemoteControlThread; + CMOOSCommClient * m_pMOOSComms; + /**method to allow Listen thread to be launched with a MOOSThread.*/ + static bool _RemoteControlCB(void* pParam) + { + CAntler* pMe = (CAntler*) pParam; + return pMe->DoRemoteControl(); + } + /** internal MOOS client callbacks*/ + static bool _MOOSConnectCB(void *pParam) + { + CAntler* pMe = (CAntler*) pParam; + return pMe->OnMOOSConnect(); + } + static bool _MOOSDisconnectCB(void *pParam) + { + CAntler* pMe = (CAntler*) pParam; + return pMe->OnMOOSDisconnect(); + } + /** main comms handling thread*/ + bool DoRemoteControl(); + /** hellos MOOSDB!*/ + bool OnMOOSConnect(); + /** goodby MOOSDB*/ + bool OnMOOSDisconnect(); + + CMOOSLock m_JobLock; + string m_sMissionFile; + bool m_bHeadless; + bool m_bQuitCurrentJob; + bool m_bSupportGentleKill; + bool m_bRunning; + bool m_bNewJob; + string m_sMonarchAntler; + bool m_bKillOnDBDisconnect; + string m_sReceivedMissionFile; + string m_sAntlerName; + string m_sDBHost; + int m_nDBPort; + + VERBOSITY_LEVEL m_eVerbosity; - }; +}; #endif diff --git a/Essentials/pAntler/AntlerMain.cpp b/Essentials/pAntler/AntlerMain.cpp index 62228e2..d88387a 100644 --- a/Essentials/pAntler/AntlerMain.cpp +++ b/Essentials/pAntler/AntlerMain.cpp @@ -50,24 +50,22 @@ CAntler gAntler; //this is a signal handler void CatchMeBeforeDeath(int sig) { - gAntler.ShutDown(); - exit(0); + gAntler.ShutDown(); + exit(0); } #endif int main(int argc ,char *argv[]) { - + #ifndef _WIN32 - //register a handler for shutdown - signal(SIGINT, CatchMeBeforeDeath); - signal( SIGQUIT, CatchMeBeforeDeath); - signal( SIGTERM, CatchMeBeforeDeath); + //register a handler for shutdown + signal(SIGINT, CatchMeBeforeDeath); + signal(SIGQUIT, CatchMeBeforeDeath); + signal(SIGTERM, CatchMeBeforeDeath); #endif - - - + //here we look for overloading directoves which are of form --name=value std::vector vArgv; std::map OverLoads; @@ -81,23 +79,23 @@ int main(int argc ,char *argv[]) std::string sVar = MOOSChomp(t,"="); if(t.empty()) { - if(MOOSStrCmp(sVar, "quiet")) - { - gAntler.SetVerbosity(CAntler::QUIET); - } - else if(MOOSStrCmp(sVar, "terse")) - { - gAntler.SetVerbosity(CAntler::TERSE); - } - else - { - MOOSTrace("error incomplete overloading of parameter --%s=value (are there extraneous whitespaces?)\n",sVar.c_str()); - return -1; - } - } + if(MOOSStrCmp(sVar, "quiet")) + { + gAntler.SetVerbosity(CAntler::QUIET); + } + else if(MOOSStrCmp(sVar, "terse")) + { + gAntler.SetVerbosity(CAntler::TERSE); + } + else + { + MOOSTrace("error incomplete overloading of parameter --%s=value (are there extraneous whitespaces?)\n",sVar.c_str()); + return -1; + } + } else { - OverLoads[sVar] = t; + OverLoads[sVar] = t; } } else @@ -108,85 +106,76 @@ int main(int argc ,char *argv[]) } - MOOSTrace("*************************************\n"); + MOOSTrace("*************************************\n"); MOOSTrace("* This is Antler, head of MOOS... *\n"); MOOSTrace("* P. Newman 2008 *\n"); MOOSTrace("*************************************\n"); - + switch(vArgv.size()) { - case 2: + case 2: + //standard principal Antler + std::string sMissionFile = vArgv[1]; + + if((int)vArgv.size()!=argc) { - //standard principal Antler - std::string sMissionFile = vArgv[1]; + //we are overloading somehow... + CProcessConfigReader MR; + MR.SetFile(sMissionFile); - if((int)vArgv.size()!=argc) - { - //we are overloading somehow... - CProcessConfigReader MR; - MR.SetFile(sMissionFile); - - sMissionFile+="++"; - - //we need to take a copy of the missions file and fill in overloads - if(!MR.MakeOverloadedCopy(sMissionFile,OverLoads)) - return MOOSFail("error making overloaded mission file\n"); - - } + sMissionFile+="++"; + + //we need to take a copy of the missions file and fill in overloads + if(!MR.MakeOverloadedCopy(sMissionFile,OverLoads)) + return MOOSFail("error making overloaded mission file\n"); - - return gAntler.Run(sMissionFile) ? 0 :-1; } - case 3: + + + return gAntler.Run(sMissionFile) ? 0 :-1; + case 3: + //standard principal Antler but only run a subset of processes + //arg 3 must be string quoted + std::string sMissionFile = vArgv[1]; + + + if((int)vArgv.size()!=argc) { - //standard principal Antler but only run a subset of processes - //arg 3 must be string quoted - std::string sMissionFile = vArgv[1]; - - - if((int)vArgv.size()!=argc) - { - //we are overloading somehow... - CProcessConfigReader MR; - MR.SetFile(sMissionFile); + //we are overloading somehow... + CProcessConfigReader MR; + MR.SetFile(sMissionFile); - sMissionFile+="++"; + sMissionFile+="++"; - //we need to take a copy of the missions file and fill in overloads - if(!MR.MakeOverloadedCopy(sMissionFile,OverLoads)) - return MOOSFail("error making overloaded mission file\n"); + //we need to take a copy of the missions file and fill in overloads + if(!MR.MakeOverloadedCopy(sMissionFile,OverLoads)) + return MOOSFail("error making overloaded mission file\n"); - } + } - //make a set of processes we want to launch - std::stringstream S(vArgv[2]); - std::set Filter; - //this rather fancy looking bit f stl simply iterates over a list of strings - std::copy(istream_iterator(S), - istream_iterator(), - std::inserter(Filter,Filter.begin())); + //make a set of processes we want to launch + std::stringstream S(vArgv[2]); + std::set Filter; + //this rather fancy looking bit f stl simply iterates over a list of strings + std::copy(istream_iterator(S), + istream_iterator(), + std::inserter(Filter,Filter.begin())); - return gAntler.Run(sMissionFile,Filter); - } - case 4: - { - //headless MOOS - driven my another Antler somewhere else - std::string sDBHost = vArgv[1]; //where is DB? - int nPort = atoi(vArgv[2].c_str()); //what port - std::string sName = vArgv[3]; //what is our Antler name? - return gAntler.Run(sDBHost,nPort,sName) ? 0 :-1; - } - default: - { - MOOSTrace("usage:\n pAntler missionfile.moos\nor\n pAntler missionfile.moos \"P1,P2,P3...\"\nor pAntler DBHost DBPort AntlerName\n"); - MOOSTrace("\n --quiet to suppress console output, --terse for limited output\n"); - - return -1; - } + return gAntler.Run(sMissionFile,Filter); + case 4: + //headless MOOS - driven my another Antler somewhere else + std::string sDBHost = vArgv[1]; //where is DB? + int nPort = atoi(vArgv[2].c_str()); //what port + std::string sName = vArgv[3]; //what is our Antler name? + return gAntler.Run(sDBHost,nPort,sName) ? 0 :-1; + default: + MOOSTrace("usage:\n pAntler missionfile.moos\nor\n pAntler missionfile.moos \"P1,P2,P3...\"\nor pAntler DBHost DBPort AntlerName\n"); + MOOSTrace("\n --quiet to suppress console output, --terse for limited output\n"); + + return -1; } - } diff --git a/Essentials/pAntler/CMakeLists.txt b/Essentials/pAntler/CMakeLists.txt index 926018d..ec2e7d7 100644 --- a/Essentials/pAntler/CMakeLists.txt +++ b/Essentials/pAntler/CMakeLists.txt @@ -4,7 +4,7 @@ set(EXECNAME pAntler) find_package(MOOS 10) #what files are needed? -SET(SRCS AntlerMain.cpp Antler.cpp) +SET(SRCS AntlerMain.cpp Antler.cpp MOOSProc.cpp) include_directories( ${${EXECNAME}_INCLUDE_DIRS} ${MOOS_INCLUDE_DIRS} ${MOOS_DEPEND_INCLUDE_DIRS}) add_executable(${EXECNAME} ${SRCS} ) diff --git a/Essentials/pAntler/MOOSProc.cpp b/Essentials/pAntler/MOOSProc.cpp new file mode 100644 index 0000000..08d46de --- /dev/null +++ b/Essentials/pAntler/MOOSProc.cpp @@ -0,0 +1,596 @@ +#include "MOOSProc.h" + + +using namespace std; + +// read the bare minimum of text to begin processing +bool CProcCfg::ParseConfig(string sConfig) +{ + + //what is its name? (if no @ symbol we just get the name and no cmdline) + m_sAppName = MOOSChomp(sConfig, "@"); + + if (m_sAppName.empty()) + { + MOOSTrace("no process specified - RUN=???\n"); + return false; + } + + //further parameters are to right of @ + string sTmp = sConfig; + + //look for tilde demarking end of param=val block + m_sParams = MOOSChomp(sTmp, "~"); + + //read the remainder + m_sMOOSName = MOOSChomp(sTmp); + + return true; + +} + + +bool CProcCfg::GetParamValue(string sParam, string &sValue) +{ + return MOOSValFromString(sValue, m_sParams, sParam, true); +} + + +// fully parse the config, looking up all references to alternate configs +bool CMOOSProc::BuildConfig() +{ + // whether to debug the launch + m_bDebugLaunch = false; + m_MissionReader->GetConfigurationParam("DebugLaunch", m_bDebugLaunch); + + + // Look for a line containing additional command line params (ExtraProcessParams) + m_CommandLineParameters.clear(); + string sExtraParamsName; + if (m_cfg.GetParamValue("ExtraProcessParams", sExtraParamsName)) + { + std::string sExtraParams; + + //OK look for this configuration string + if (!m_MissionReader->GetConfigurationParam(sExtraParamsName, sExtraParams)) + return MOOSFail(" warning cannot find extra parameters named \"%s\"\n", + sExtraParamsName.c_str()); + + // convert commas to spaces + while (!sExtraParams.empty()) + m_CommandLineParameters.push_back(MOOSChomp(sExtraParams, ",")); + } + + // Inhibit MOOS params? + m_bInhibitMOOSParams = false; + MOOSValFromString(m_bInhibitMOOSParams, m_cfg.m_sParams, "InhibitMOOSParams", true); + + //by default process are assumed to be on the system path + //users can specify an alternative path for all process by setting + // "ExectutablePath=" in the mission file configuration block. + //user has the option of specifying paths individually process by process. + //alternativelt they can specify that a particular process should be located by + // system wide and not in the default executable path + string sSpecifiedPath; + m_cfg.m_sAppPath = m_cfg.m_sAppName; + if (!m_cfg.GetParamValue("PATH", sSpecifiedPath)) + { + //we just use the Antler-wide Exepath + m_cfg.m_sAppPath = m_cfg.m_sExecPath + m_cfg.m_sAppName; + } + else + { + if (!MOOSStrCmp(sSpecifiedPath, "SYSTEM")) + { + //we are being told to look in a special place + m_cfg.m_sAppPath = sSpecifiedPath + "/" + m_cfg.m_sAppName; + } + // otherwise it's up to the SYSTEM, so do nothing + } + + + //here we figure out what MOOS name is implied if none is given (thanks to N.P and F.A) + if (m_cfg.m_sMOOSName.empty()) + { + std::string sTmp = m_cfg.m_sAppName; + while (sTmp.rfind('/') != string::npos) + { + sTmp = sTmp.substr(sTmp.rfind('/') + 1); + } + + if (sTmp.empty()) + { + // ended with a / ? + MOOSTrace("Error in configuration -MOOS Name cannot end in \" / \" : %s\n", + m_cfg.m_sAppName.c_str()); + return false; + } + m_cfg.m_sMOOSName = sTmp; + } + + + + // other stuff + + return this->BuildConfigSpecific(); +} + + + +#ifdef _WIN32 + +CMOOSProcWin32::~CMOOSProcWin32() +{ + delete m_pWin32Attrib; + delete m_pWin32Proc; +} + + +bool CMOOSProcWin32::BuildConfigSpecific() +{ + + + return this->BuildConfigSpecific2(); +} + +bool CMOOSProcConsoleWin32::BuildConfigSpecific2() +{ + if (MOOSValFromString(sLaunchConfigurationName, sParam, "Win32Config")) + { + //OK look for this configuration string + if (!m_MissionReader->GetConfigurationParam(sLaunchConfigurationName, + sLaunchConfiguration)) + return MOOSFail(" warning: could not find resource string called \"%s\"\n", + sLaunchConfigurationName.c_str()) ; + + // which is ridiculous, because we can't do anything with it + } + else + { + if (IsMOOSDB(sAppName)) + { + this->m_ConsoleFlags.push_back(BACKGROUND_BLUE); + } + + if (IsIRemote(sAppName)) + { + this->m_ConsoleFlags.push_back(BACKGROUND_RED); + } + } + + return true; +} + +bool CMOOSProcWin32::Start(bool bGentle) +{ + try + { + // make the command line ProcessBinaryName MissionFile ProcessMOOSName + string sCmd = this->m_sApp + " "; + if (!this->m_bInhibitMOOSParams) + sCmd += this->MissionFile() + " " + this->m_sMOOSName + " "; + + //continuing this task, here we pass extra parameters to the MOOS process if required + for (STRING_LIST::iterator p = this->m_CommandLineParameters.begin(); + p != this->m_ExtraCommandLineParameters.end(); + p++) + { + sCmd += *p + " "; + } + + //make a new process attributes class + this->m_pWin32Attrib = NULL; + this->m_pWin32Attrib = new XPCProcessAttrib(NULL, (char *)sCmd.c_str()); + this->m_pWin32Attrib->vSetCreationFlag(this->CreationFlags()); + + //we shall use our own start up image as a starting point + STARTUPINFO StartUp; + GetStartupInfo (&StartUp); + + //set up the title + StartUp.lpTitle = (char*)this->m_sApp.c_str(); + + //set up white text + StartUp.dwFillAttribute = + FOREGROUND_INTENSITY | + FOREGROUND_BLUE | + FOREGROUND_RED | + FOREGROUND_GREEN | + BACKGROUND_INTENSITY ; + + + //give users basic control over backgroun as an RGB combination + for (DWORD_LIST::iterator q = this->m_ConsoleFlags.begin(); + q != this->m_ConsoleFlags.end(); + q++) + { + StartUp.dwFillAttribute |= *q; + StartUp.dwFlags |= STARTF_USEFILLATTRIBUTE; + } + + this->m_pWin32Attrib->vSetStartupInfo(&StartUp); + + //no create an object capable of laucnhing win32 processes + this->m_pWin32Proc = NULL; + this->m_pWin32Proc = new XPCProcess(* this->m_pWin32Attrib); + + //go! + this->m_pWin32Proc->vResume(); + + } + catch (XPCException & e) + { + if (this->m_pWin32Attrib != NULL) + { + delete this->m_pWin32Attrib; + } + if (this->m_pWin32Proc != NULL) + { + delete this->m_pWin32Proc; + } + MOOSTrace("*** %s Launch Failed:***\n\a\a", this->m_sApp.c_str()); + MOOSTrace("%s\n", e.sGetException()); + return false; + } + + return true; + +} + + +bool CMOOSProcWin32::Stop(bool bGentle) +{ + m_pWin32Proc->vTerminate(); + m_pWin32Proc->vWaitForTerminate(100); + return true; +} + +bool CMOOSProcWin32::IsStopped() +{ + return m_pWin32Proc->dwGetExitCode() != STILL_ACTIVE; +} + + + +#else // NIX DEFINITIONS + + + + +bool CMOOSProcNix::BuildConfigSpecific() +{ + return true; +} + +bool CMOOSProcConsoleNix::BuildConfigSpecific() +{ + string sLaunchConfigurationName; + string sLaunchConfiguration; + + + if (m_cfg.GetParamValue("XConfig", sLaunchConfigurationName)) + { + //OK look for this configuration string + if (!m_MissionReader->GetConfigurationParam(sLaunchConfigurationName, + sLaunchConfiguration)) + return MOOSFail(" warning: could not find resource string called \"%s\"\n", + sLaunchConfigurationName.c_str()) ; + } + else + { + //some applications are v.important in MOOS + // -- if not told otherwise they get special colours + string sBgColor = "#DDDDFF"; + string sFgColor = "#000000"; + + if (IsIRemote()) + { + sBgColor = "#CC0000"; + sFgColor = "#FFFFFF"; + } + + if (IsMOOSDB()) + { + sBgColor = "#003300"; + sFgColor = "#FFFFFF"; + } + + string sLabel = m_cfg.m_sMOOSName.empty() + ? "" + : MOOSFormat("as MOOSName \"%s\"", m_cfg.m_sMOOSName.c_str()).c_str(); + + sLaunchConfiguration = "-geometry," + + MOOSFormat("80x12+2+%d", (*(m_cfg.m_nCurrentLaunch)) * 50) + + ",+sb," + + ",-fg," + sFgColor + + ",-bg," + sBgColor + + ",-T," + MOOSFormat("%s %s", GetAppName().c_str(), sLabel.c_str()); + + } + + //OK now simply chomp our way through a space delimited list... + while (!sLaunchConfiguration.empty()) + { + MOOSTrimWhiteSpace(sLaunchConfiguration); + // convert commas to spaces + string sP = MOOSChomp(sLaunchConfiguration, ","); + MOOSTrimWhiteSpace(sP); + if (!sP.empty()) + m_ConsoleLaunchParameters.push_back(sP); + } + + return true; + +} + +bool CMOOSProcScreenNix::BuildConfigSpecific() +{ + string sLaunchConfigurationName; + string sLaunchConfiguration; + + + if (m_cfg.GetParamValue("ScreenConfig", sLaunchConfigurationName)) + { + //OK look for this configuration string + // likely they would add -L for loggging, or -l/-ln for shell login options + if (!m_MissionReader->GetConfigurationParam(sLaunchConfigurationName, + sLaunchConfiguration)) + return MOOSFail(" warning: could not find resource string called \"%s\"\n", + sLaunchConfigurationName.c_str()) ; + } + + //OK now simply chomp our way through a space delimited list... + while (!sLaunchConfiguration.empty()) + { + MOOSTrimWhiteSpace(sLaunchConfiguration); + // convert commas to spaces + string sP = MOOSChomp(sLaunchConfiguration, ","); + MOOSTrimWhiteSpace(sP); + if (!sP.empty()) + m_ScreenLaunchParameters.push_back(sP); + } + return true; +} + + +bool CMOOSProcNixBase::Start(bool bGentle) +{ + + //make a child process + this->m_ChildPID = fork(); + if (this->m_ChildPID < 0) + { + //hell! + MOOSTrace("fork failed, not good\n"); + return false; + } + + if (this->m_ChildPID == 0) + { + //I'm the child now.. + + // build m_FullCommandLine according to launch type + m_FullCommandLine.clear(); + this->StartSpecific(); + + if (!m_FullCommandLine.size()) + { + MOOSTrace("pAntler author error: no elements in m_FullCommandLine!\n"); + return false; + } + + // CONVERT STRING LIST TO ARRAY + const char ** pExecVParams = new const char* [m_FullCommandLine.size() + 1]; + int i = 0; + for (STRING_LIST::iterator s = this->m_FullCommandLine.begin(); + s != this->m_FullCommandLine.end(); + ++s) + { + pExecVParams[i++] = s->c_str(); + } + + //terminate list + pExecVParams[i++] = NULL; + if(m_bDebugLaunch) + { + for (int j = 0; j < i; j++) + MOOSTrace("argv[%d]:\"%s\"\n", j, pExecVParams[j]); + } + + //and finally replace ourselves with a new xterm process image + char * const * pParamList = const_cast (pExecVParams); + if (execvp(pExecVParams[0], pParamList) == -1) + { + MOOSTrace("Failed exec - not good. Called exec as follows:\n"); + exit(EXIT_FAILURE); + + } + + } + + //Parent execution stream continues here... + //we need to change the process group of the spawned process so that ctrl-C + //does get sent to all the launched xterms. Instead we will catch ctrl-C ourself + //and find the MOOS process running within the sub process, signal it to die + //so subprocesses can clean up nicely + if (bGentle) + setpgid(this->m_ChildPID, 0); + + return true; + +} + +bool CMOOSProcNix::StartSpecific() +{ + + m_FullCommandLine.push_back(m_cfg.m_sAppPath); + + if (!this->m_bInhibitMOOSParams) + { + //we do the usual thing of supplying Mission file and MOOSName + + m_FullCommandLine.push_back(this->MissionFile()); + m_FullCommandLine.push_back(m_cfg.m_sMOOSName); + } + + //here we pass extra parameters to the MOOS process if required + m_FullCommandLine.splice(m_FullCommandLine.end(), m_CommandLineParameters); + + + return true; +} + +bool CMOOSProcConsoleNix::StartSpecific() +{ + + // xterm -e + m_FullCommandLine.push_back(DEFAULT_NIX_TERMINAL); + m_FullCommandLine.splice(m_FullCommandLine.end(), m_ConsoleLaunchParameters); + m_FullCommandLine.push_back("-e"); + + + // this is the same as the plain-vanilla nix launch + m_FullCommandLine.push_back(m_cfg.m_sAppPath); + + if (!this->m_bInhibitMOOSParams) + { + //we do the usual thing of supplying Mission file and MOOSName + + m_FullCommandLine.push_back(this->MissionFile()); + m_FullCommandLine.push_back(m_cfg.m_sMOOSName); + } + + //here we pass extra parameters to the MOOS process if required + m_FullCommandLine.splice(m_FullCommandLine.end(), m_CommandLineParameters); + + return true; +} + +bool CMOOSProcScreenNix::StartSpecific() +{ + // screen -dmS + m_FullCommandLine.push_back("screen"); + m_FullCommandLine.push_back("-DmS"); + m_FullCommandLine.push_back(m_cfg.m_sMOOSName); + + m_FullCommandLine.splice(m_FullCommandLine.end(), m_ScreenLaunchParameters); + + + // this is the same as the plain-vanilla nix launch + m_FullCommandLine.push_back(m_cfg.m_sAppPath); + + if (!this->m_bInhibitMOOSParams) + { + //we do the usual thing of supplying Mission file and MOOSName + + m_FullCommandLine.push_back(this->MissionFile()); + m_FullCommandLine.push_back(m_cfg.m_sMOOSName); + } + + //here we pass extra parameters to the MOOS process if required + m_FullCommandLine.splice(m_FullCommandLine.end(), m_CommandLineParameters); + + return true; +} + + +bool CMOOSProcNixBase::Stop(bool bGentle) +{ + bool ret = this->StopSpecific(bGentle); + + //just give it a little time - for pities sake - no need for this pause + MOOSPause(300); + + return ret; +} + +bool CMOOSProcNix::StopSpecific(bool bGentle) +{ + kill(m_ChildPID, SIGTERM); + + return true; +} + +bool CMOOSProcConsoleNix::StopSpecific(bool bGentle) +{ + if (bGentle) + { + kill(m_ChildPID, SIGTERM); + } + else + { + //we need to be crafty.... + string sCmd = "ps -e -o ppid= -o pid="; + + FILE* In = popen(sCmd.c_str(), "r"); + + if (In == NULL) return false; + + bool bFound = false; + char Line[256]; + while (fgets(Line, sizeof(Line), In)) + { + stringstream L(Line); + int ppid, pid; + L >> ppid; + L >> pid; + + if (m_ChildPID == ppid) + { + kill(pid, SIGTERM); + bFound = true; + } + } + pclose(In); + return bFound; + } + + return true; +} + +bool CMOOSProcScreenNix::StopSpecific(bool bGentle) +{ + if (bGentle) + { + kill(m_ChildPID, SIGTERM); + } + else + { + //we need to be crafty.... + string sCmd = "ps -e -o ppid= -o pid="; + + FILE* In = popen(sCmd.c_str(), "r"); + + if (In == NULL) return false; + + bool bFound = false; + char Line[256]; + while (fgets(Line, sizeof(Line), In)) + { + stringstream L(Line); + int ppid, pid; + L >> ppid; + L >> pid; + + if (m_ChildPID == ppid) + { + kill(pid, SIGTERM); + bFound = true; + } + } + pclose(In); + return bFound; + } + + return true; +} + + +bool CMOOSProcNixBase::IsStopped() +{ + int nStatus = 0; + return waitpid(this->m_ChildPID, &nStatus, WNOHANG) > 0; +} + + +#endif diff --git a/Essentials/pAntler/MOOSProc.h b/Essentials/pAntler/MOOSProc.h new file mode 100644 index 0000000..10b0cd5 --- /dev/null +++ b/Essentials/pAntler/MOOSProc.h @@ -0,0 +1,234 @@ +/* + * MOOSProc.h + * MOOS + * + * Created by Ian Katz on 2013-10-27 + * Based on code from pnewman on 18/04/2008. + * + */ + + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#ifndef MOOSPROCH +#define MOOSPROCH + +#include "MOOS/libMOOS/MOOSLib.h" +#include + + +#ifdef _WIN32 +#include "XPCProcess.h" +#include "XPCProcessAttrib.h" +#include "XPCException.h" +#else +#include +#include +#include +#include +#endif + +using namespace std; + +#define DEFAULT_NIX_TERMINAL "xterm" + +// data structure for the "RUN = ..." line in a pAntler config +class CProcCfg +{ +public: + CProcCfg() {}; + CProcCfg(string sConfig) { ParseConfig(sConfig); }; + ~CProcCfg() {}; + + // keep attributes public + string m_sAppName; // executable name + string m_sAppPath; // full path to app + string m_sMOOSName; // run-as name of app + string m_sMissionFile; // path to mission file + string m_sParams; // key-val parameters from config line + + // SPECIAL USE + string m_sExecPath; // "SYSTEM", or prefix to executables + int* m_nCurrentLaunch; // pointer to number of launches + + // read in all data + bool ParseConfig(string sConfig); + + // get a value from the parsed data + bool GetParamValue(string sParam, string &sValue); + +}; + + + +// data structure for a process instantiated from RUN line +class CMOOSProc +{ +public: + CMOOSProc(CProcCfg config, CProcessConfigReader* MissionReader) + : m_cfg(config), m_MissionReader(MissionReader) {}; + virtual ~CMOOSProc() {}; + + bool BuildConfig(); + + virtual bool BuildConfigSpecific() = 0; + virtual bool Start(bool bGentle) = 0; + virtual bool Stop(bool bGentle) = 0; + virtual bool IsStopped() = 0; + + string MissionFile() { return m_MissionReader->GetFileName(); }; + bool IsMOOSDB() { return MOOSStrCmp("MOOSDB", m_cfg.m_sAppName); }; + bool IsIRemote() { return MOOSStrCmp("iRemote", m_cfg.m_sAppName); }; + + string GetAppName() { return m_cfg.m_sAppName; }; + string GetMOOSName() { return m_cfg.m_sMOOSName; }; + +protected: + + CProcCfg m_cfg; + + CProcessConfigReader* m_MissionReader; + + // settings from more in-depth parsing + bool m_bDebugLaunch; + bool m_bInhibitMOOSParams; + STRING_LIST m_CommandLineParameters; + + + // conditional compilation to hold OS-specific program launch info +#ifdef _WIN32 + XPCProcess * m_pWin32Proc; + XPCProcessAttrib * m_pWin32Attrib; +#else + pid_t m_ChildPID; + +public: + pid_t GetChildPID() { return m_ChildPID; }; + +#endif + +}; + + + +#ifdef _WIN32 + +typedef std::list DWORD_LIST; + +class CMOOSProcWin32 : public CMOOSProc +{ +public: + CMOOSProcWin32(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProc(config, MissionReader) {}; + virtual ~CMOOSProcWin32(); + + // value passed to vSetCreationFlag + virtual DWORD CreationFlags() { return CREATE_SUSPENDED; }; + + virtual bool BuildConfigSpecific(); + virtual bool BuildConfigSpecific2() + { return true; }; // for console, we ignore it in this instance + + virtual bool Start(bool bGentle); + virtual bool Stop(bool bGentle); + virtual bool IsStopped(); + +protected: + // unused in this instance, but placed here to cut down on duplicate code + DWORD_LIST m_ConsoleFlags; + +}; + + +class CMOOSProcConsoleWin32 : public CMOOSProcWin32 +{ +public: + CMOOSProc(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProcProcWin32Base(config, MissionReader) {}; + virtual ~CMOOSProc() {}; + + virtual bool BuildConfigSpecific2(string sConfig); + virtual DWORD CreationFlags() { return CREATE_NEW_CONSOLE | CREATE_SUSPENDED; }; + +}; + + +#else + +class CMOOSProcNixBase : public CMOOSProc +{ +public: + CMOOSProcNixBase(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProc(config, MissionReader) {}; + virtual ~CMOOSProcNixBase() {}; + + // we add a 300ms pause after the "stop" signal on *nix + virtual bool Stop(bool bGentle); + virtual bool StopSpecific(bool bGentle) = 0; + + // we need to do more sophisticated things with the command line + virtual bool Start(bool bGentle); + virtual bool StartSpecific() = 0; + + virtual bool IsStopped(); + +protected: + // for all *nix processes, this will be the master arg list + // that gets converted into the execvp arg list + STRING_LIST m_FullCommandLine; +}; + + +class CMOOSProcNix : public CMOOSProcNixBase +{ +public: + CMOOSProcNix(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProcNixBase(config, MissionReader) {}; + virtual ~CMOOSProcNix() {}; + + virtual bool BuildConfigSpecific(); + virtual bool StartSpecific(); + virtual bool StopSpecific(bool bGentle); +}; + + +class CMOOSProcConsoleNix : public CMOOSProcNixBase +{ +public: + CMOOSProcConsoleNix(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProcNixBase(config, MissionReader) {}; + virtual ~CMOOSProcConsoleNix() {}; + + virtual bool BuildConfigSpecific(); + virtual bool StartSpecific(); + virtual bool StopSpecific(bool bGentle); + +protected: + // parameters specifically for an xterm launch, preceding the "-e" + STRING_LIST m_ConsoleLaunchParameters; +}; + + +class CMOOSProcScreenNix : public CMOOSProcNixBase +{ +public: + CMOOSProcScreenNix(CProcCfg config, CProcessConfigReader* MissionReader) + : CMOOSProcNixBase(config, MissionReader) {}; + virtual ~CMOOSProcScreenNix() {}; + + virtual bool BuildConfigSpecific(); + virtual bool StartSpecific(); + virtual bool StopSpecific(bool bGentle); + +protected: + // parameters specifically for a screen launch, preceding the command (and args) + STRING_LIST m_ScreenLaunchParameters; +}; + + +#endif // _WIN32 + + +#endif // ifndef MOOSPROCH diff --git a/Essentials/pAntler/test-antler-nix.moos b/Essentials/pAntler/test-antler-nix.moos new file mode 100644 index 0000000..cc94e08 --- /dev/null +++ b/Essentials/pAntler/test-antler-nix.moos @@ -0,0 +1,35 @@ +ProcessConfig = ANTLER +{ + MSBetweenLaunches = 1000 + + DebugLaunch = false + + Run = MOOSDB @ LaunchType=Screen + + Run = xmessage @ NewConsole = false,XConfig=xconfig1 ~ xmessage-moosfile-moosname + + param_oldplaunch = launched,with,NewConsole=False + param_oldclaunch = launched,with,NewConsole=True + param_newplaunch = launched,with,LaunchType=Process + param_newclaunch = launched,with,LaunchType=Console + param_newslaunch = launched,with,LaunchType=Screen + + Run = xmessage @ NewConsole = true, InhibitMOOSParams=true,ExtraProcessParams=param_oldplaunch ~ xmessage-oldlaunch-process + Run = xmessage @ NewConsole = false, InhibitMOOSParams=true,ExtraProcessParams=param_oldclaunch ~ xmessage-oldlaunch-console + Run = xmessage @ LaunchType = Process, InhibitMOOSParams=true,ExtraProcessParams=param_newplaunch ~ xmessage-newlaunch-process + Run = xmessage @ LaunchType = Console, InhibitMOOSParams=true,ExtraProcessParams=param_newclaunch ~ xmessage-newlaunch-console + Run = xmessage @ LaunchType = Screen, InhibitMOOSParams=true,ExtraProcessParams=param_newslaunch ~ xmessage-newlaunch-screen + + param_xconfig = launched,with,xconfig + xconfig1 = -geometry,40x40+0+20 + Run = xmessage @ LaunchType=Console,XConfig=xconfig1,ExtraProcessParams=param_xconfig ~ xmessage-xconfig + + + Run = /usr/bin/xmessage @ InhibitMOOSParams=true, ExtraProcessParams=fullpath,NewConsole = false ~ xmessage-fullpath + fullpath = launched,with,full,path,to,executable + + Run = screen @ InhibitMOOSParams=true, ExtraProcessParams=screensummary,Xconfig=screenconsole,LaunchType=Console ~ screen-summary + screensummary = -ls + screenconsole = -hold,-geometry,120x20+0+20 + +}