MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Essentials/pAntler/Antler.cpp
Go to the documentation of this file.
00001 #include "Antler.h"
00002 
00003 using namespace std;
00004 #include <sstream>
00005 #include <iostream>
00006 #include <sstream>
00007 #include <string>
00008 #include <iterator>
00009 #include <algorithm>
00010 
00011 
00012 
00013 
00014 #define DEBUG_LAUNCH 0
00015 CAntler::CAntler()
00016 {
00017 
00018         
00019         m_JobLock.UnLock();    
00020     m_bNewJob = false;
00021     m_sAntlerName = "Monarch";
00022     m_sDBHost = "localhost";
00023     m_nDBPort = 9000;
00024     m_bQuitCurrentJob = false;
00025         m_eVerbosity=CHATTY;
00026 }
00027 
00028 //this is the vanilla version of Run - called to run from a single mission file
00029 bool CAntler::Run(const std::string &  sMissionFile,std::set<std::string> Filter )
00030 {
00031     m_bHeadless = false;
00032     m_sMissionFile = sMissionFile;
00033     m_Filter = Filter;
00034     return Spawn(m_sMissionFile);
00035 }
00036 
00037 //this version will wait for a mission fiel to be sent via a DB
00038 bool CAntler::Run(const std::string & sHost,  int nPort, const std::string & sAntlerName)
00039 {
00040     //this is more interesting...
00041     m_sAntlerName = sAntlerName;
00042     m_sDBHost = sHost;
00043     m_nDBPort = nPort;
00044     m_bHeadless = true;
00045     
00046     
00047     if(!ConfigureMOOSComms())
00048         return true;
00049         
00050     
00051     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);
00052     
00053        
00054         const char * sSpin = "-\\|/";
00055     while(1)
00056     {
00057         //wait to be signalled that there is work to do...
00058         int i = 0;
00059         while(!m_bNewJob)
00060         {
00061             MOOSPause(500);
00062             MOOSTrace("   Speak to me Monarch....%c\r",sSpin[i++%3]);
00063         }
00064             
00065         //no more launching until this community is complete
00066         m_JobLock.Lock();
00067         Spawn(m_sReceivedMissionFile,true);
00068         m_bNewJob = false;
00069         m_JobLock.UnLock();
00070         
00071     }
00072 }
00073 
00074 
00075 
00076 bool CAntler::DoRemoteControl()
00077 {
00078     
00079     
00080             
00081     while(1)
00082     {
00083         MOOSPause(100);
00084         if(!m_pMOOSComms->IsConnected())
00085             continue;
00086         
00087         //better check mail
00088         MOOSMSG_LIST NewMail;
00089         if(m_pMOOSComms->Fetch(NewMail))
00090         {
00091             CMOOSMsg Msg;
00092             if(m_bHeadless)
00093             {
00094                 
00095                 if(m_pMOOSComms->PeekMail(NewMail,"MISSION_FILE",Msg))
00096                 {
00097                     MOOSTrace("\n|***** Dynamic Brief *****|\n\n");
00098                     
00099                     //make a new file name
00100                     m_sReceivedMissionFile = MOOSFormat("runtime_%s.moos",MOOSGetTimeStampString().c_str());   
00101                     
00102                     MOOSTrace("   %s received [%d bytes]\n",m_sReceivedMissionFile.c_str(),Msg.GetString().size());
00103                     MOOSTrace("   shutting down all current spawned processes:\n");
00104                     
00105                     //tell the current job to quit
00106                     m_bQuitCurrentJob = true;
00107                     
00108                     //wait for that to happen
00109                     m_JobLock.Lock();        
00110                     
00111                     //here we copy the mission file contained in the message to 
00112                     std::stringstream ss(Msg.GetString());
00113                     
00114                     //suck out the Antler filter line
00115                     std::string sFilter;
00116                     std::getline(ss, sFilter);
00117                                         MOOSTrace("%s\n", sFilter.c_str());
00118                     MOOSChomp(sFilter,"ANTLERFILTER:", true);
00119                     std::stringstream ssF(sFilter);
00120                     
00121                     //fill in the filter set
00122                     std::copy(istream_iterator<std::string>(ssF), 
00123                               istream_iterator<string>(),
00124                               std::inserter(m_Filter,m_Filter.begin()));
00125                     
00126                     
00127                     //write out the whole file
00128                     std::ofstream Out(m_sReceivedMissionFile.c_str());
00129                     if(!Out.is_open())
00130                     {
00131                         m_JobLock.UnLock();
00132                         return MOOSFail("failed to open mission file for writing");
00133                     }
00134                     
00135                     //you've gotta lurve C++ ...
00136                     Out<<ss.rdbuf();
00137                     
00138                     Out.close();
00139                     
00140                     //we no longer want the current job to quit (it already has)
00141                     m_bQuitCurrentJob = false;
00142                     
00143                     //signal that we have more work to do
00144                     m_bNewJob =true;
00145                     
00146                     //let thread 0 continue
00147                     m_JobLock.UnLock();
00148                     
00149                     
00150                 }
00151             }
00152             else
00153             {
00154                 if(m_pMOOSComms->PeekAndCheckMail(NewMail, "ANTLER_STATUS", Msg))
00155                 {
00156                     std::string sWhat;
00157                     MOOSValFromString(sWhat, Msg.GetString(),"Action");
00158                     std::string sProc;
00159                     MOOSValFromString(sProc, Msg.GetString(),"Process");
00160                     std::string sID;
00161                     MOOSValFromString(sID, Msg.GetString(), "AntlerID");
00162                     
00163                     MOOSTrace("   [rmt] Process %-15s has %s (by %s)\n",sProc.c_str(),sWhat.c_str(),sID.c_str());
00164                 }    
00165             }
00166             
00167         }
00168     }        
00169 }
00170 
00171 bool CAntler::SetVerbosity(VERBOSITY_LEVEL eLevel)
00172 {
00173         m_eVerbosity = eLevel;
00174         switch(eLevel)
00175         {
00176                 case CHATTY:
00177                         break;
00178                 case TERSE:
00179                         InhibitMOOSTraceInThisThread(true);
00180                         break;
00181                 case QUIET:
00182                         InhibitMOOSTraceInThisThread(true);
00183                         if(m_pMOOSComms!=NULL)
00184                                 m_pMOOSComms->SetQuiet(true);
00185                         
00186         }
00187         return true;
00188 }
00189 
00190 bool CAntler::ConfigureMOOSComms()
00191 {
00192     
00193         
00194     
00195     //start a monitoring thread
00196     m_RemoteControlThread.Initialise(_RemoteControlCB, this);
00197     m_RemoteControlThread.Start();
00198     
00199     
00200     m_pMOOSComms = new CMOOSCommClient;
00201     m_pMOOSComms->SetOnConnectCallBack(_MOOSConnectCB,this);
00202         m_pMOOSComms->SetOnDisconnectCallBack(_MOOSDisconnectCB,this);
00203     m_pMOOSComms->SetQuiet(true);
00204     
00205     std::string sMe =MOOSFormat("Antler{%s}",m_sAntlerName.c_str());
00206     
00207     //try and connect to a DB
00208     if(!m_pMOOSComms->Run(m_sDBHost.c_str(), (long int)m_nDBPort, sMe.c_str(), 1))
00209         return MOOSFail("could not set up MOOSComms\n");
00210     
00211       
00212     return true;
00213 }
00214 
00215 
00216 
00217 bool CAntler::SendMissionFile( )
00218 {
00219     MOOSTrace("\n\n|***** Propagate *****|\n\n");
00220     CMOOSFileReader FR;
00221     FR.SetFile(m_sMissionFile);
00222     std::stringstream ss;
00223 
00224     //copy the filters in
00225     ss<<"ANTLERFILTER:";
00226     std::copy (m_Filter.begin(), m_Filter.end(), ostream_iterator <std::string> (ss, " "));
00227     ss<<std::endl;
00228     
00229     while(!FR.eof())
00230     {
00231         std::string sL = FR.GetNextValidLine()+"\n";
00232         ss<<sL;
00233     }
00234     m_pMOOSComms->Notify("MISSION_FILE",ss.str());
00235     
00236     
00237     MOOSTrace("   Monarch published thinned mission file [%d bytes]\n\n",ss.str().size());
00238     return true;
00239     
00240 }
00241 bool CAntler::OnMOOSConnect()
00242 {
00243     if(m_bHeadless)
00244     {
00245         MOOSTrace("  Connecting to a DB\n");    
00246         m_pMOOSComms->Register("MISSION_FILE",0);
00247       
00248     }
00249     else
00250     {
00251         m_pMOOSComms->Register("ANTLER_STATUS",0);
00252         SendMissionFile();
00253     }
00254     return true;
00255 }
00256 bool CAntler::OnMOOSDisconnect()
00257 {
00258     if(m_bHeadless)
00259     {
00260         
00261         MOOSTrace("   DB Connection Lost\n");    
00262         
00263         if(m_bKillOnDBDisconnect)
00264         {
00265             //look likes the monarch is dead.....
00266             MOOSTrace("   shutting down all current spawned processes:\n");
00267             
00268             //tell the current job to quit
00269             m_bQuitCurrentJob = true;
00270             
00271             //wait for that to happen
00272             m_JobLock.Lock();        
00273             m_JobLock.UnLock();        
00274         }
00275        
00276     }
00277     return true;
00278 }
00279 
00280 bool CAntler::PublishProcessQuit(const std::string & sProc)
00281 {
00282         if(!m_bHeadless)
00283         return false;
00284     
00285     if(!m_pMOOSComms->IsConnected())
00286         return false;
00287 
00288     m_pMOOSComms->Notify("ANTLER_STATUS",MOOSFormat("Action=Quit,Process=%s,AntlerID=%s",sProc.c_str(),m_sAntlerName.c_str()));
00289     
00290     
00291     return true;
00292 }
00293 
00294 bool CAntler::PublishProcessLaunch(const std::string & sProc)
00295 {
00296         if(!m_bHeadless)
00297         return false;
00298     
00299     if(!m_pMOOSComms->IsConnected())
00300         return false;
00301     
00302     m_pMOOSComms->Notify("ANTLER_STATUS",MOOSFormat("Action=Launched,Process=%s,AntlerID=%s",sProc.c_str(),m_sAntlerName.c_str()));
00303     
00304     return true;
00305 }
00306 
00307 
00308 bool CAntler::KillNicely(MOOSProc* pProc)
00309 {
00310 #ifndef _WIN32
00311                 
00312         if(m_bSupportGentleKill)
00313         {
00314                 if(pProc->m_bNewConsole)
00315                 {
00316                         //we need to be crafty....
00317                         std::string sCmd = "ps -e -o ppid= -o pid=";
00318                         
00319                         FILE* In = popen(sCmd.c_str(),"r");
00320                         
00321                         if(In!=NULL)
00322                         {
00323                                 bool bFound = false;
00324                                 char Line[256];
00325                                 while(fgets(Line,sizeof(Line),In))
00326                                 {
00327                                         std::stringstream L(Line);
00328                                         int ppid,pid;
00329                                         L>>ppid;
00330                                         L>>pid;
00331                                         
00332                                         if(pProc->m_ChildPID==ppid)
00333                                         {
00334                                                 kill(pid,SIGTERM);
00335                                                 bFound = true;
00336                                         }
00337                                 }       
00338                                 pclose(In);
00339                                 return bFound;
00340                         }
00341                         else
00342                         {
00343                                 return false;
00344                         }
00345                 }
00346                 else
00347                 {
00348                         //the proc ID we have is of the actuall MOOSProcess and not its parent
00349                         //we can just kill it...
00350                         kill(pProc->m_ChildPID,SIGTERM);
00351                 }
00352         }
00353         else
00354         {
00355                 kill(pProc->m_ChildPID,SIGTERM);
00356         }
00357 #else
00358         //MOOSTrace("Warning - gentle killing of win32 processes is not implemented\n");
00359         pProc->pWin32Proc->vTerminate();   
00360     return true;
00361 
00362 #endif
00363         return true;
00364 }
00365 
00366 
00367 bool CAntler::Spawn(const std::string &  sMissionFile, bool bHeadless)
00368 {
00369     
00370     MOOSTrace("\n\n|****** Launch ******|\n\n");
00371     m_nCurrentLaunch = 0;
00372     
00373     
00374     //set up the mission file reader
00375     if(!m_MissionReader.SetFile(sMissionFile))
00376         return MOOSFail("error reading mission file\n");
00377     
00378     
00379     m_MissionReader.SetAppName("ANTLER"); //NB no point in running under another name...(I guess Anter1 could launch Antler2 though...)
00380     
00381     STRING_LIST      sParams;
00382     
00383     if(!m_MissionReader.GetConfiguration(  m_MissionReader.GetAppName(),sParams))
00384         return MOOSFail("error reading antler config block from mission file\n");
00385     
00386     
00387     //fetch all the lines in teg Antler configuration block
00388     STRING_LIST::iterator p;
00389     sParams.reverse();
00390     
00391     int nTimeMSBetweenSpawn=DEFAULTTIMEBETWEENSPAWN;
00392     m_MissionReader.GetConfigurationParam("MSBetweenLaunches",nTimeMSBetweenSpawn);
00393     
00394     //here we'll figure out a what paths to use when looking for  executables
00395     m_sDefaultExecutablePath = "SYSTEMPATH";
00396     m_MissionReader.GetConfigurationParam("ExecutablePath",m_sDefaultExecutablePath);
00397     
00398     if(!MOOSStrCmp("SYSTEMPATH",m_sDefaultExecutablePath))
00399     {
00400         //MOOSTrace("\"ExecutablePath\" is %s\n",m_sDefaultExecutablePath.c_str());
00401         if(*m_sDefaultExecutablePath.rbegin()!='/')
00402         {
00403             //look to add extra / if needed
00404             m_sDefaultExecutablePath+='/';
00405         }
00406         
00407     }
00408     else
00409     {
00410         MOOSTrace("Unless directed otherwise using system path to locate binaries \n");
00411         m_sDefaultExecutablePath="";
00412     }
00413     
00414         
00415         //are we being ask to support gentle process killing?
00416 #ifdef _WIN32
00417         m_bSupportGentleKill= false;
00418 #else
00419         m_bSupportGentleKill = true;
00420         m_MissionReader.GetConfigurationParam("GentleKill",m_bSupportGentleKill);
00421 #endif
00422         
00423         
00424         
00425         //no cycle through each line in the configuration block. If it begins with run then it means launch
00426     for(p = sParams.begin();p!=sParams.end();p++)
00427     {
00428         std::string sLine = *p;
00429         
00430         std::string sWhat = MOOSChomp(sLine,"=");
00431         
00432         if(MOOSStrCmp(sWhat,"RUN"))
00433         {
00434             //OK we are being asked to run a process
00435             
00436             //try to create a process
00437             MOOSProc* pNew  = CreateMOOSProcess(sLine);
00438             
00439             if(pNew!=NULL)
00440             {
00441                                 //this a really important bit of text most folk will want to see it...
00442                                 InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET);
00443                                 {
00444                                         MOOSTrace("   [%.3d] Process: %-15s ~ %-15s launched successfully\n",
00445                                                           m_nCurrentLaunch,
00446                                                           pNew->m_sApp.c_str(),
00447                                                           pNew->m_sMOOSName.c_str());
00448                                 }
00449                                 InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY);
00450                                 
00451                 m_ProcList.push_front(pNew);
00452                                 m_nCurrentLaunch++;
00453                 PublishProcessLaunch(pNew->m_sApp);
00454             }
00455             
00456                 //wait a while
00457             MOOSPause(nTimeMSBetweenSpawn);
00458             
00459         }
00460     }
00461     
00462     
00463     
00464     if(bHeadless==false)
00465     {
00466         bool bMaster=false;
00467         m_MissionReader.GetConfigurationParam("EnableDistributed",bMaster);
00468         if(bMaster)
00469         {
00470             
00471             m_MissionReader.GetValue("ServerHost",m_sDBHost);
00472             m_MissionReader.GetValue("ServerPort",m_nDBPort);
00473             
00474             
00475             if(!ConfigureMOOSComms())
00476                 return MOOSFail("failed to start MOOS comms");
00477             
00478         }
00479     }
00480     else
00481     {
00482         m_bKillOnDBDisconnect = true;
00483         m_MissionReader.GetConfigurationParam("KillOnDBDisconnect",m_bKillOnDBDisconnect);
00484     }
00485     
00486 
00487     
00488     //now wait on all our processes to close....
00489     while(m_ProcList.size()!=0)
00490     {
00491         MOOSPROC_LIST::iterator q;
00492         
00493         for(q = m_ProcList.begin();q!=m_ProcList.end();q++)
00494         {
00495             MOOSProc * pMOOSProc = *q;
00496             
00497 #ifdef _WIN32
00498             if(m_bQuitCurrentJob)
00499             {
00500                                 KillNicely(pMOOSProc);
00501             }
00502             
00503             
00504             pMOOSProc->pWin32Proc->vWaitForTerminate(100);
00505             if(    pMOOSProc->pWin32Proc->dwGetExitCode()!=STILL_ACTIVE)
00506             {
00507 
00508                                 //this a really important bit of text most folk will want to see it...
00509                                 InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET);
00510                                 {
00511                                         MOOSTrace("   [%.3d] Process: %-15s has quit\n",
00512                                                           --m_nCurrentLaunch,
00513                                                           pMOOSProc->m_sApp.c_str());
00514                                 }
00515                                 InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY);
00516 
00517                 
00518                 PublishProcessQuit(pMOOSProc->m_sApp);
00519                 delete pMOOSProc->pWin32Attrib;
00520                 delete pMOOSProc->pWin32Proc;
00521                 delete pMOOSProc;
00522                 
00523                 m_ProcList.erase(q);
00524                 break;
00525             }
00526 #else
00527             if(m_bQuitCurrentJob)
00528             {
00529                 MOOSTrace("   actively killing running child %s\n",pMOOSProc->m_sApp.c_str());
00530                                 KillNicely(pMOOSProc);
00531                 //just give it a little time - for pities sake - no need for this pause
00532                 MOOSPause(300);
00533             }
00534             
00535             
00536             int nStatus = 0;
00537             if(waitpid(pMOOSProc->m_ChildPID,&nStatus,WNOHANG)>0)
00538             {
00539                                 
00540                                 InhibitMOOSTraceInThisThread(m_eVerbosity==QUIET);
00541                                 {
00542                                         MOOSTrace("   [%.3d] Process: %-15s has quit\n",
00543                                                           --m_nCurrentLaunch,
00544                                                           pMOOSProc->m_sApp.c_str());
00545                                 }
00546                                 InhibitMOOSTraceInThisThread(m_eVerbosity!=CHATTY);
00547                                 
00548                 
00549                 PublishProcessQuit(pMOOSProc->m_sApp);
00550                 
00551                 m_ProcList.erase(q);
00552                 break;
00553             }
00554             MOOSPause(100);
00555 #endif
00556             
00557         }
00558               
00559     }
00560     
00561 
00562     
00563     return 0;
00564     
00565 }
00566 
00567 
00568 
00569 
00570 bool CAntler::MakeExtraExecutableParameters(std::string sParam,STRING_LIST & ExtraCommandLineParameters,std::string sProcName,std::string sMOOSName)
00571 {
00572     
00573     ExtraCommandLineParameters.clear();
00574     
00575     std::string sExtraParamsName;
00576     if(!MOOSValFromString(sExtraParamsName, sParam, "ExtraProcessParams", true))
00577         return true;//nothing to do
00578     
00579     std::string sExtraParams;
00580     
00581     //OK look for this configuration string
00582     if(!m_MissionReader.GetConfigurationParam(sExtraParamsName,sExtraParams))
00583         return MOOSFail("   warning cannot find extra parameters named \"%s\"\n",sExtraParamsName.c_str());
00584     
00585     while(!sExtraParams.empty())
00586         ExtraCommandLineParameters.push_back(MOOSChomp(sExtraParams,","));
00587     
00588     return true;
00589     
00590 }
00591 
00592 bool CAntler::MakeConsoleLaunchParams(std::string sParam,STRING_LIST & LaunchList,std::string sProcName,std::string sMOOSName)
00593 {
00594     //sParam is a string in the Run=ProcName @ sParam ~ MOOSName
00595     std::string sLaunchConfigurationName;
00596     std::string sLaunchConfiguration;
00597 #ifdef _WIN32
00598         bool bNIX = false;
00599         
00600 #else
00601         bool bNIX= true; 
00602 #endif
00603     
00604     
00605         std::string sLaunchKey = bNIX?"XConfig":"Win32Config"; 
00606     if(!MOOSValFromString(sLaunchConfigurationName, sParam, sLaunchKey))
00607     {
00608         //some applications are v.important in MOOS if not told otherwise they get special colours
00609                 string sBgColor = bNIX? "#DDDDFF" : "";
00610                 string sFgColor = bNIX? "#000000" : "";
00611         
00612         if(MOOSStrCmp(sProcName,"iRemote"))
00613         {
00614                         sBgColor = bNIX ? "#CC0000" : "RED";
00615                         sFgColor = bNIX ? "#FFFFFF" : "";
00616         }
00617         if(MOOSStrCmp(sProcName,"MOOSDB"))
00618         {
00619                         sBgColor = bNIX? "#003300" : "BLUE";
00620                         sFgColor = bNIX? "#FFFFFF" : "";
00621         }
00622         if(bNIX)
00623                 {
00624                         sLaunchConfiguration = "-geometry,"+MOOSFormat("80x12+2+%d",(m_nCurrentLaunch++)*50)+
00625                         ",+sb,"+
00626                         ",-fg,"+sFgColor+
00627                         ",-bg,"+sBgColor+
00628                         ",-T,"+MOOSFormat("%s %s",sProcName.c_str(),sMOOSName.empty()?"":MOOSFormat("as MOOSName \"%s\"",sMOOSName.c_str()).c_str());
00629                 }
00630                 else
00631                 {
00632                         sLaunchConfiguration = sBgColor;
00633                 }
00634     }
00635     else
00636     {
00637         
00638         //OK look for this configuration string
00639         if(!m_MissionReader.GetConfigurationParam(sLaunchConfigurationName,sLaunchConfiguration))
00640                         return MOOSFail("   warning: could not find resource string called \"%s\"",sLaunchConfigurationName.c_str()) ;
00641     }
00642     
00643     //OK now simply chomp our way through a space delimited list...
00644     while(!sLaunchConfiguration.empty())
00645     {
00646         MOOSTrimWhiteSpace(sLaunchConfiguration);
00647         std::string sP = MOOSChomp(sLaunchConfiguration,",");
00648         MOOSTrimWhiteSpace(sP);
00649         if(!sP.empty())
00650                 LaunchList.push_back(sP);
00651     }
00652     
00653     return !LaunchList.empty();
00654     
00655     
00656 }
00657 
00658 
00659 
00660 CAntler::MOOSProc* CAntler::CreateMOOSProcess(string sConfiguration)
00661 {
00662     
00663     
00664     //what tis its name? (if no @ symbol we just get the name and no cmdline)
00665     string sProcName = MOOSChomp(sConfiguration,"@");
00666     
00667     //further parameters are to left left of @
00668     string sParam = sConfiguration;
00669     
00670     if(sProcName.empty())
00671     {
00672         MOOSTrace("no process specified - RUN=???\n");
00673         return NULL;
00674     }
00675     
00676     //std::string sFullProcName = m_sDefaultExecutablePath+sProcName;
00677     
00678     //if things go well this will eventually point to a new Process
00679     MOOSProc * pNewProc    = NULL;
00680     
00681         //look for tilde demarking end of param=val block
00682     string sOption = MOOSChomp(sParam,"~");
00683     
00684     
00685     
00686     bool bDistributed=false;
00687     m_MissionReader.GetConfigurationParam("EnableDistributed",bDistributed);
00688 
00689     if(bDistributed)
00690     {
00691                
00692         
00693         if(m_bHeadless)
00694         {
00695             //we are a drone
00696             std::string sAntlerRequired;
00697             if(!MOOSValFromString(sAntlerRequired, sOption, "AntlerID", true))
00698                 return NULL; //this is for primary Antler
00699             
00700                         
00701             if(!MOOSStrCmp(sAntlerRequired, m_sAntlerName))
00702                 return NULL; //for some other Antler
00703             
00704             //OK it is for us...
00705             //MOOSTrace("Headless Antler found a RUN directive...\n");
00706         }
00707         else
00708         {
00709             //we are a TopMOOS
00710             std::string sAntlerRequired;
00711             if(MOOSValFromString(sAntlerRequired, sOption, "AntlerID", true))
00712                 return NULL; //this is for a drone
00713             
00714         }
00715     }
00716     else
00717     {
00718         //we run everything
00719     }
00720     
00721     //do we want a new console?
00722     bool bNewConsole = false;
00723         MOOSValFromString(bNewConsole, sOption, "NEWCONSOLE",true);
00724     
00725     //do we want to inhibit the passing of MOOS parameters (mission file and MOOSName)
00726     bool bInhibitMOOSParams = false;
00727     MOOSValFromString(bInhibitMOOSParams, sOption, "InhibitMOOSParams", true);
00728     
00729     //by default process are assumed to be on the system path
00730     //users can specify an alternative path for all process by setting "ExectutablePath=<Path>" in the mission file
00731     //configuration block.
00732         //user has the option of specifying paths individually process by process.
00733     //alternativelt they can specify that a particular process shouod be located by  system wide and not
00734     //in the default executable path
00735     std::string sSpecifiedPath;
00736     std::string sFullProcName=sProcName;
00737     if(MOOSValFromString(sSpecifiedPath, sOption, "PATH",true))
00738     {
00739         if(MOOSStrCmp(sSpecifiedPath,"SYSTEM"))
00740         {
00741                 //do nothing - the system should know where to look 
00742         }
00743         else
00744         {
00745             //ok we are being told to look in a special place
00746             sFullProcName=sSpecifiedPath+"/"+sProcName;
00747         }
00748     }
00749     else
00750     {
00751         //we just use the Anter-wide Exepath
00752         sFullProcName = m_sDefaultExecutablePath+sProcName;
00753     }
00754     
00755     //name of process as registered...is the first param after "~"
00756     string sMOOSName = MOOSChomp(sParam);
00757     
00758     //here we figure out what MOOS name is implied if none is given (thanks to N.P and F.A)
00759     if(sMOOSName.empty())
00760         {
00761         std::string sTmp = sProcName;
00762         if(sTmp.rfind('/') != string::npos) 
00763         {
00764             sTmp = sTmp.substr(sTmp.rfind('/')+1);
00765         }
00766         if(sTmp.empty()) 
00767         { 
00768             // ended with a / ?
00769             MOOSTrace("Error in configuration  -MOOS Name cannot end in \" / \" : %s\n",sProcName.c_str());
00770             return NULL;
00771         }
00772         sMOOSName = sTmp;
00773         }
00774     
00775     
00776     //here we bail according to our filters 
00777     if(!m_Filter.empty() && m_Filter.find(sMOOSName)==m_Filter.end())
00778     {
00779         return NULL;
00780     }
00781         
00782     //it is pssible to specifiy complicated parameters to the process being launched. (For example
00783     //xterm being passed a whole load of configurations and then the name of the MOOS process it should
00784     //itself launch. This next call fills in a string list of such parameters
00785     STRING_LIST sLaunchParams;
00786     if(bNewConsole)
00787         MakeConsoleLaunchParams(sOption, sLaunchParams,sProcName,sMOOSName);
00788     
00789     
00790     //here we figure what extra command line parameters should be given to the MOOS Process
00791     //being launched.
00792     STRING_LIST ExtraCommandLineParameters;
00793     MakeExtraExecutableParameters(sOption,ExtraCommandLineParameters,sProcName,sMOOSName);
00794     
00795     
00796     
00797     //All good up to here, now make a new process info holder stucture...
00798     pNewProc = new MOOSProc;
00799     pNewProc->m_sApp = sFullProcName;
00800     pNewProc->m_ExtraCommandLineParameters =ExtraCommandLineParameters;
00801     pNewProc->m_ConsoleLaunchParameters = sLaunchParams;
00802     pNewProc->m_bInhibitMOOSParams = bInhibitMOOSParams;
00803         pNewProc->m_sMOOSName = sMOOSName;
00804     pNewProc->m_bNewConsole = bNewConsole;
00805     pNewProc->m_sMissionFile = m_MissionReader.GetFileName();
00806     
00807     //finally spawn each according to his own
00808 #ifndef _WIN32
00809     if(DoNixOSLaunch(pNewProc))
00810 #else
00811         if(DoWin32Launch(pNewProc))
00812 #endif
00813         {
00814             return pNewProc;
00815         }
00816         else
00817         {        
00818             delete pNewProc;
00819             return NULL;
00820         }
00821 }
00822 
00823 
00824 bool CAntler::ShutDown()
00825 {
00826         
00827         MOOSPROC_LIST::iterator q;
00828 
00829         MOOSTrace("\n\n|***** Shutdown *****|\n\n");
00830 
00831         for(q = m_ProcList.begin();q!=m_ProcList.end();q++)
00832         {
00833                 MOOSProc * pMOOSProc = *q;
00834 
00835                 if(KillNicely(pMOOSProc))
00836                 {
00837          
00838                         int nStatus = 0;
00839 #ifndef _WIN32
00840                         
00841                         MOOSTrace("\n   Signalling %-15s ",pMOOSProc->m_sApp.c_str());
00842                         if(waitpid(pMOOSProc->m_ChildPID,&nStatus,0)>0)
00843                         {
00844                                 MOOSTrace("[OK]");
00845                         }               
00846 #endif
00847                 }
00848 
00849          }
00850         
00851         MOOSTrace("\n\n   All spawned processes shutdown.\n\n   That was the MOOS \n\n");
00852          
00853          
00854         return true;
00855 }
00856 
00857 
00858 
00859 #ifdef _WIN32
00860 bool CAntler::DoWin32Launch(CAntler::MOOSProc * pNewProc)
00861 {
00862     
00863     
00864     try
00865     {
00866         
00867         // make the command line ProcessBinaryName MissionFile ProcessMOOSName
00868         string sCmd = pNewProc->m_sApp+" ";
00869         if(pNewProc->m_bInhibitMOOSParams==false)
00870             sCmd+=pNewProc->m_sMissionFile+" "+pNewProc->m_sMOOSName+" ";
00871         
00872         //continuing this task, here we pass extra parameters to the MOOS process if required
00873                 for(STRING_LIST::iterator p = pNewProc->m_ExtraCommandLineParameters.begin();p!=pNewProc->m_ExtraCommandLineParameters.end();p++)
00874         {
00875             sCmd+=*p+" ";
00876         }
00877         
00878         
00879         //make a new process attributes class
00880         pNewProc->pWin32Attrib = NULL;
00881         pNewProc->pWin32Attrib = new XPCProcessAttrib(NULL,(char *)sCmd.c_str());
00882         
00883         if(pNewProc->m_bNewConsole)
00884         {
00885             pNewProc->pWin32Attrib->vSetCreationFlag(CREATE_NEW_CONSOLE | CREATE_SUSPENDED);        
00886         }
00887         else
00888         {
00889             pNewProc->pWin32Attrib->vSetCreationFlag(CREATE_SUSPENDED);
00890         }
00891         
00892         
00893         //we shall use our own start up image as a starting point
00894         STARTUPINFO StartUp;
00895         GetStartupInfo (&StartUp);
00896         
00897         //set up the title
00898         StartUp.lpTitle = (char*)pNewProc->m_sApp.c_str();
00899         
00900         //set up white text
00901         StartUp.dwFillAttribute = 
00902         FOREGROUND_INTENSITY| 
00903         FOREGROUND_BLUE |
00904         FOREGROUND_RED |
00905         FOREGROUND_GREEN|
00906         BACKGROUND_INTENSITY ;
00907         
00908         
00909                 //give users basic control over backgroun as an RGB combination
00910         for(STRING_LIST::iterator q=pNewProc->m_ConsoleLaunchParameters.begin();q!=pNewProc->m_ConsoleLaunchParameters.end();q++)
00911         {
00912             if(MOOSStrCmp(*q, "BACKGROUND_BLUE"))
00913             {
00914                 StartUp.dwFillAttribute|=BACKGROUND_BLUE;
00915                 StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE;
00916             }
00917             if(MOOSStrCmp(*q, "BACKGROUND_GREEN"))
00918             {
00919                 StartUp.dwFillAttribute|=BACKGROUND_GREEN;
00920                 StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE;
00921             }
00922             if(MOOSStrCmp(*q, "BACKGROUND_RED"))
00923             {
00924                 StartUp.dwFillAttribute|=BACKGROUND_RED;
00925                 StartUp.dwFlags|=STARTF_USEFILLATTRIBUTE;
00926             }
00927             
00928         }
00929         
00930         pNewProc->pWin32Attrib->vSetStartupInfo(&StartUp);
00931         
00932         //no create an object capable of laucnhing win32 processes
00933         pNewProc->pWin32Proc = NULL;
00934         pNewProc->pWin32Proc =new XPCProcess(* pNewProc->pWin32Attrib);
00935         
00936         //go!
00937         pNewProc->pWin32Proc->vResume();
00938         
00939     }
00940     catch (XPCException & e)
00941     {
00942         if(pNewProc->pWin32Attrib!=NULL)
00943         {
00944             delete pNewProc->pWin32Attrib;
00945         }
00946         if(pNewProc->pWin32Proc!=NULL)
00947         {
00948             delete pNewProc->pWin32Proc;
00949         }
00950         MOOSTrace("*** %s Launch Failed:***\n\a\a",pNewProc->m_sApp.c_str());
00951         MOOSTrace("%s\n",e.sGetException());
00952         return false;
00953     }
00954     
00955     return true;
00956     
00957 }
00958 #else
00959 
00960 bool CAntler::DoNixOSLaunch(CAntler::MOOSProc * pNewProc)
00961 {
00962     
00963     //make a child process
00964     if((pNewProc->m_ChildPID = fork())<0)
00965     {
00966         //hell!
00967         MOOSTrace("fork failed, not good\n");
00968         return false;
00969     }
00970     else if(pNewProc->m_ChildPID ==0)
00971     {
00972         //I'm the child now..
00973         
00974         STRING_LIST::iterator p = pNewProc->m_ConsoleLaunchParameters.begin();
00975         unsigned int nExecParams = pNewProc->m_ConsoleLaunchParameters.size()+pNewProc->m_ExtraCommandLineParameters.size()+ 6;
00976         const char ** pExecVParams = new const char* [nExecParams];
00977         int i = 0;
00978         
00979         //do we need to configure an xterm?
00980         if(pNewProc->m_bNewConsole)
00981         {
00982             pExecVParams[i++] = DEFAULT_NIX_TERMINAL; 
00983             if(!pNewProc->m_ConsoleLaunchParameters.empty())
00984             {
00985                 while(p!=pNewProc->m_ConsoleLaunchParameters.end())
00986                 {
00987                     pExecVParams[i++] = (p++->c_str());
00988                 }
00989             }
00990             
00991             pExecVParams[i++] = "-e";
00992             
00993         }
00994         
00995         //here we fill in the process name we really care about
00996         pExecVParams[i++] = (pNewProc->m_sApp.c_str()) ;
00997         if(!pNewProc->m_bInhibitMOOSParams)
00998         {
00999             //we do the usual thing of supplying Mission file and MOOSName
01000             pExecVParams[i++] = pNewProc->m_sMissionFile.c_str(); 
01001             pExecVParams[i++] = pNewProc->m_sMOOSName.c_str(); 
01002         }
01003         
01004         
01005         //here we pass extra parameters to the MOOS process if required
01006         for(p = pNewProc->m_ExtraCommandLineParameters.begin();p!=pNewProc->m_ExtraCommandLineParameters.end();p++)
01007         {
01008             pExecVParams[i++] = (p->c_str());
01009         }
01010         
01011         //terminate list
01012         pExecVParams[i++] = NULL;
01013 #if(DEBUG_LAUNCH)
01014         for(int j = 0;j<i;j++)
01015             MOOSTrace("argv[%d]:\"%s\"\n",j,pExecVParams[j]);
01016 #endif
01017         
01018         //and finally replace ourselves with a new xterm process image
01019         char * const * pParamList = const_cast<char * const *> (pExecVParams);
01020         if(execvp(pExecVParams[0], pParamList)==-1)
01021         {
01022             MOOSTrace("Failed exec - not good. Called exec as follows:\n");
01023             exit(EXIT_FAILURE);
01024             
01025         }
01026         
01027     }
01028     
01029     //Parent execution stream continues here...
01030         //we need to change the process group of the spawned process so that ctrl-C
01031         //does get sent to all the launched xterms. Instead we will catch ctrl-C ourself
01032         //and find the MOOS process running within the sub process, signal it to die
01033         //so subprocesses can clean up nicely
01034         if(m_bSupportGentleKill)
01035                 setpgid(pNewProc->m_ChildPID,0);
01036     
01037     return true;
01038 }
01039 
01040 #endif
01041 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines