MOOS 0.2375
|
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