MOOS 0.2375
|
00001 00002 // 00003 // MOOS - Mission Oriented Operating Suite 00004 // 00005 // A suit of Applications and Libraries for Mobile Robotics Research 00006 // Copyright (C) 2001-2005 Massachusetts Institute of Technology and 00007 // Oxford University. 00008 // 00009 // This software was written by Paul Newman at MIT 2001-2002 and Oxford 00010 // University 2003-2005. email: pnewman@robots.ox.ac.uk. 00011 // 00012 // This file is part of a MOOS Core Component. 00013 // 00014 // This program is free software; you can redistribute it and/or 00015 // modify it under the terms of the GNU General Public License as 00016 // published by the Free Software Foundation; either version 2 of the 00017 // License, or (at your option) any later version. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 // General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with this program; if not, write to the Free Software 00026 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00027 // 02111-1307, USA. 00028 // 00030 // MOOSBridge.cpp: implementation of the CMOOSBridge class. 00031 // 00033 00034 #include "MOOSBridge.h" 00035 #include "MOOSCommunity.h" 00036 00038 // Construction/Destruction 00040 00041 #define DEFAULT_BRIDGE_FREQUENCY 20 00042 #define DEFAULT_UDP_PORT 10000 00043 00044 #define BOUNCE_WITH_GUSTO 0 00045 using namespace std; 00046 00047 CMOOSBridge::CMOOSBridge() 00048 { 00049 m_nBridgeFrequency = DEFAULT_BRIDGE_FREQUENCY; 00050 m_sLocalCommunity = "#1"; 00051 } 00052 00053 CMOOSBridge::~CMOOSBridge() 00054 { 00055 00056 } 00057 00058 bool CMOOSBridge::Run(const string &sMissionFile,const string & sMOOSName) 00059 { 00060 if(!m_MissionReader.SetFile(sMissionFile)) 00061 return false; 00062 00063 m_MissionReader.SetAppName(sMOOSName); 00064 00065 if(!Configure()) 00066 { 00067 return MOOSFail("MOOSBridge failed to configure itself - probably a configuration block error\n");; 00068 } 00069 while(1) 00070 { 00071 MarshallLoop(); 00072 MOOSPause(50); 00073 } 00074 return true; 00075 } 00076 00077 00078 bool CMOOSBridge::MarshallLoop() 00079 { 00080 COMMUNITY_MAP::iterator p,q; 00081 MOOSMSG_LIST InMail; 00082 for(p = m_Communities.begin();p!=m_Communities.end();p++) 00083 { 00084 CMOOSCommunity* pSrcCommunity = (p->second); 00085 00086 if(pSrcCommunity->Fetch(InMail)) 00087 { 00088 int nMail = InMail.size(); 00089 for(q = m_Communities.begin();q!=m_Communities.end();q++) 00090 { 00091 CMOOSCommunity* pDestCommunity = q->second; 00092 if(pDestCommunity!=pSrcCommunity) 00093 { 00094 MOOSMSG_LIST::iterator w; 00095 for(w = InMail.begin();w!=InMail.end();w++) 00096 { 00097 00098 CMOOSCommunity::SP Index(w->GetKey(),pSrcCommunity->GetCommunityName() ); 00099 00100 if(pDestCommunity->WantsToSink(Index)) 00101 { 00102 //decrement mail count 00103 nMail--; 00104 00105 CMOOSMsg MsgCopy = *w; 00106 MsgCopy.m_sKey = pDestCommunity->GetAlias(Index); 00107 if(IsUDPShare(Index)) 00108 { 00109 if(pDestCommunity->HasUDPConfigured()) 00110 { 00111 #if(BOUNCE_WITH_GUSTO) 00112 MOOSTrace("UDP posting %s to community %s@%s:%d as %s (source community is %s)\n", 00113 w->GetKey().c_str(), 00114 pDestCommunity->GetCommunityName().c_str(), 00115 pDestCommunity->GetUDPHost().c_str(), 00116 pDestCommunity->GetUDPPort(), 00117 MsgCopy.m_sKey.c_str(), 00118 w->GetCommunity().c_str()); 00119 #endif 00120 00121 //Send via UDP (directed to single machine and port) - fire and forget... 00122 m_UDPLink.Post(MsgCopy,pDestCommunity->GetUDPHost(),pDestCommunity->GetUDPPort()); 00123 } 00124 else 00125 { 00126 MOOSTrace("cannot send %s via UDP to %s - destination community has no UDP port\n",MsgCopy.m_sKey.c_str(),pDestCommunity->GetFormattedName().c_str()); 00127 } 00128 } 00129 else 00130 { 00131 pDestCommunity->Post(MsgCopy); 00132 } 00133 #if(BOUNCE_WITH_GUSTO) 00134 MOOSTrace("Bouncing %s in %s -> %s on %s t = %f\n", 00135 w->GetKey().c_str(), 00136 pSrcCommunity->GetFormattedName().c_str(), 00137 MsgCopy.GetKey().c_str(), 00138 pDestCommunity->GetFormattedName().c_str(), 00139 MsgCopy.GetTime()); 00140 #endif 00141 } 00142 } 00143 } 00144 } 00145 //here we could look for broadcasts... 00146 } 00147 } 00148 00149 00150 //have we received any UDP mail? if so it was meant for our own DB 00151 //remember if UDP is being used there MUST be one MOOSBridge per community 00152 MOOSMSG_LIST UDPMail; 00153 00154 if(m_UDPLink.Fetch(UDPMail)) 00155 { 00156 //find our local community 00157 00158 COMMUNITY_MAP::iterator qq = m_Communities.find(m_sLocalCommunity ); 00159 if(qq!=m_Communities.end()) 00160 { 00161 CMOOSCommunity * pLocalCommunity = qq->second; 00162 MOOSMSG_LIST::iterator p; 00163 for(p = UDPMail.begin();p!=UDPMail.end();p++) 00164 { 00165 #if(BOUNCE_WITH_GUSTO) 00166 MOOSTrace("Received %s from %s on UDP - inserting into %s\n",p->GetKey().c_str(), p->GetCommunity().c_str(),pLocalCommunity->GetFormattedName().c_str()); 00167 #endif 00168 00169 //now be careful we aren't looking to subscribing for this mail....now that would be some horrible positive 00170 //feedback loop! Can alos check as mikerb suggess on source community - it must not 00171 //be us! 00172 00173 if(!pLocalCommunity->HasMOOSSRegistration(p->GetKey()) && pLocalCommunity->GetCommunityName()!= p->GetCommunity() ) 00174 { 00175 pLocalCommunity->Post(*p); 00176 } 00177 else 00178 { 00179 00180 MOOSTrace("no way!\n"); 00181 } 00182 } 00183 } 00184 00185 } 00186 00187 return true; 00188 } 00189 00190 bool CMOOSBridge::IsUDPShare(CMOOSCommunity::SP & Index) 00191 { 00192 return !m_UDPShares.empty() && m_UDPShares.find(Index)!=m_UDPShares.end(); 00193 } 00194 00195 bool CMOOSBridge::Configure() 00196 { 00197 STRING_LIST sParams; 00198 00199 if(!m_MissionReader.GetConfiguration(m_MissionReader.GetAppName(),sParams)) 00200 return MOOSFail("ERROR - Could not find a configuration block called %s \n",m_MissionReader.GetAppName().c_str()) ; 00201 00202 //if user set LOOPBACK = TRUE then both src and destination communities can be identical 00203 //default is FALSE this means if src=dest then the bridging will be ignored 00204 bool bAllowLoopBack = false; 00205 m_MissionReader.GetConfigurationParam("LOOPBACK",bAllowLoopBack); 00206 00207 00208 //capture default file scope settings - maybe useful later 00209 string sLocalHost = "LOCALHOST"; 00210 string sLocalPort = "9000"; 00211 00212 if(!m_MissionReader.GetValue("COMMUNITY",m_sLocalCommunity)) 00213 { 00214 MOOSTrace("WARNING : Cannot read ::MOOS-scope variable COMMUNITY - assuming %s\n",m_sLocalCommunity.c_str()); 00215 } 00216 00217 if(!m_MissionReader.GetValue("SERVERPORT",sLocalPort)) 00218 { 00219 MOOSTrace("WARNING :Cannot read ::MOOS-scope variable SERVERPORT - assuming %s\n",sLocalPort.c_str()); 00220 } 00221 00222 if(!m_MissionReader.GetValue("SERVERHOST",sLocalHost)) 00223 { 00224 MOOSTrace("WARNING :Cannot read ::MOOS-scope variable SERVERHOST - assuming %s\n",sLocalHost.c_str()); 00225 } 00226 00227 //how fast should the bridge operate in Hz (setting this to zero is a special case and 00228 //makes all registrations with dfPeriod = 0) 00229 m_nBridgeFrequency = DEFAULT_BRIDGE_FREQUENCY; 00230 m_MissionReader.GetConfigurationParam("BridgeFrequency",m_nBridgeFrequency); 00231 00232 00233 STRING_LIST::iterator q; 00234 00235 for(q = sParams.begin();q!=sParams.end();q++) 00236 { 00237 string sLine = *q; 00238 //NB is alias's aren't specified the sink name is the source name 00239 //also you don't need as many alias's as sources... 00240 //SHARE = COMMUNITYNAME@HOSTNAME:PORT [VAR1,VAR2,VAR3,....] -> COMMUNITYNAME@HOSTNAME:PORT [VarAlias1,....] 00241 // or using mission file defaults i.e file scope constants 00242 //SHARE = [VAR1,VAR2,VAR3,....] -> COMMUNITYNAME@HOSTNAME:PORT [VarAlias1,....] 00243 string sCmd = MOOSChomp(sLine,"="); 00244 00245 if(MOOSStrCmp(sCmd,"SHARE") || MOOSStrCmp(sCmd,"UDPSHARE") ) 00246 { 00247 bool bUDP = MOOSStrCmp(sCmd,"UDPSHARE"); 00248 00249 string sSrc = MOOSChomp(sLine,"->"); 00250 string sDest = sLine; 00251 00252 string sSrcCommunity =m_sLocalCommunity ; 00253 string sSrcCommunityHost = sLocalHost; 00254 string sSrcCommunityPort = sLocalPort; 00255 if(sSrc[0]=='[') 00256 { 00257 00258 //tell user what we are doing - this is the short-hand set up... 00259 MOOSTrace("Using abbreviated configuration protocol Source: %s@%s:%s\n", 00260 sSrcCommunity.c_str(), 00261 sSrcCommunityPort.c_str(), 00262 sSrcCommunityHost.c_str()); 00263 00264 00265 MOOSChomp(sSrc,"["); 00266 } 00267 else 00268 { 00269 sSrcCommunity = MOOSChomp(sSrc,"@"); 00270 sSrcCommunityHost = MOOSChomp(sSrc,":"); 00271 sSrcCommunityPort = MOOSChomp(sSrc,"["); 00272 } 00273 00274 string sVars =MOOSChomp(sSrc,"]"); 00275 00276 string sDestCommunity = MOOSChomp(sDest,"@"); 00277 string sDestCommunityHost = MOOSChomp(sDest,":"); 00278 string sDestCommunityPort = MOOSChomp(sDest,"["); 00279 string sAliases = MOOSChomp(sDest,"]"); 00280 00281 //look for loopback - not always wanted 00282 if(MOOSStrCmp(sDestCommunityHost,sSrcCommunityHost) && 00283 MOOSStrCmp(sDestCommunityPort,sSrcCommunityPort)) 00284 { 00285 if(bAllowLoopBack==false) 00286 { 00287 MOOSTrace("\t Ignoring Loop Back - (bridge not built)\n"); 00288 continue; 00289 } 00290 } 00291 00292 //convert to numeric after format checking 00293 long lSrcPort=0; 00294 if(sSrcCommunity.empty() || sSrcCommunityHost.empty() ||sSrcCommunityPort.empty()) 00295 { 00296 MOOSTrace("error on SHARED configuration %s\n correct line format is \nSHARE = COMMUNITYNAME@HOSTNAME:PORT [VAR1,VAR2,VAR3,....] -> COMMUNITYNAME@HOSTNAME:PORT\n",q->c_str()); 00297 continue; 00298 } 00299 else 00300 { 00301 lSrcPort = atoi(sSrcCommunityPort.c_str()); 00302 } 00303 00304 long lDestPort=0; 00305 if(sDestCommunity.empty() || sDestCommunityHost.empty() ||sDestCommunityPort.empty()) 00306 { 00307 MOOSTrace("error on SHARED configuration %s\n correct line format is \nSHARE = COMMUNITYNAME@HOSTNAME:PORT [VAR1,VAR2,VAR3,....] -> COMMUNITYNAME@HOSTNAME:PORT\n",q->c_str()); 00308 continue; 00309 } 00310 else 00311 { 00312 lDestPort = atoi(sDestCommunityPort.c_str()); 00313 } 00314 00315 //we will force all broadcast address directives to be the same "community" called "ALL" 00316 if(MOOSStrCmp(sDestCommunityHost, "BROADCAST") || MOOSStrCmp(sDestCommunity, "ALL")) 00317 { 00318 //this is trixksy - need to qualify this generic address with the a port so each Bridge can 00319 //UDP broadcast to multiple addresses 00320 sDestCommunity="ALL"; 00321 sDestCommunityHost = "BROADCAST-"+sDestCommunityPort; 00322 } 00323 00324 //make two communities (which will be bridged) 00325 CMOOSCommunity* pSrcCommunity = GetOrMakeCommunity(sSrcCommunity); 00326 00327 CMOOSCommunity* pDestCommunity = GetOrMakeCommunity(sDestCommunity); 00328 00329 if(!bUDP) 00330 { 00331 //depending on what kind of share this is we may want to simply specify 00332 //a UDP end point or start a MOOS client 00333 00334 //we will register with each DB with a unique name 00335 std::string sFullyQualifiedMOOSName = m_MissionReader.GetAppName()+"@"+m_sLocalCommunity; 00336 00337 00338 //for (connecting to) the source community (where messages come from) 00339 if(!pSrcCommunity->IsMOOSClientRunning()) 00340 { 00341 pSrcCommunity->InitialiseMOOSClient(sSrcCommunityHost, 00342 lSrcPort, 00343 sFullyQualifiedMOOSName, 00344 m_nBridgeFrequency); 00345 } 00346 00347 //for (connecting to) the destination community (where messages go to) 00348 if(!pDestCommunity->IsMOOSClientRunning()) 00349 { 00350 pDestCommunity->InitialiseMOOSClient(sDestCommunityHost, 00351 lDestPort, 00352 sFullyQualifiedMOOSName, 00353 m_nBridgeFrequency); 00354 } 00355 00356 } 00357 else 00358 { 00359 //MOOSTrace("Setting UDP port for community %s as %s:%d\n",pDestCommunity->GetCommunityName().c_str(),sDestCommunityHost.c_str(),lDestPort); 00360 if(sDestCommunityHost.find("BROADCAST-")!=std::string::npos && MOOSStrCmp(sDestCommunity,"ALL")) 00361 { 00362 //this is special 00363 pDestCommunity->SetUDPInfo("255.255.255.255", lDestPort); 00364 } 00365 else 00366 { 00367 pDestCommunity->SetUDPInfo(sDestCommunityHost, lDestPort); 00368 } 00369 } 00370 00371 //populate bridge with variables to be shared (including translation) 00372 if(pSrcCommunity && pDestCommunity) 00373 { 00374 string sVar = MOOSChomp(sVars,","); 00375 while(!sVar.empty()) 00376 { 00377 pSrcCommunity->AddSource(sVar); 00378 CMOOSCommunity::SP Index(sVar,pSrcCommunity->GetCommunityName() ); 00379 pDestCommunity->AddSink(Index,MOOSChomp(sAliases,",")); 00380 00381 if(bUDP) 00382 { 00383 //we need to store in the Bridge class what variables appearing in our 00384 //local community we are asked to forward on via UDP to some other 00385 //commnity 00386 m_UDPShares.insert(Index); 00387 } 00388 00389 //suck another VAR 00390 sVar = MOOSChomp(sVars,","); 00391 } 00392 } 00393 } 00394 00395 } 00396 00398 //MOOSBridge. If poepl wnat UDP bridging they need on pMOOSBridge per community (ie the 00399 //toplogy of N communities and just 1 bridge is not allowed 00400 int nLocalUDPPort = DEFAULT_UDP_PORT; 00401 if(m_MissionReader.GetConfigurationParam("UDPListen",nLocalUDPPort) ) 00402 { 00403 //start the UDP listener 00404 m_UDPLink.Run(nLocalUDPPort); 00405 00406 } 00407 else 00408 { 00409 MOOSTrace("warning no UDPListen port specified for local community - outgoing UDP comms only\n"); 00410 00411 //passing run with a -1 port means build the socket but don't bind or start a listen thread 00412 m_UDPLink.Run(-1); 00413 } 00414 //ensure we have at least the local MOOS-enabled community in existence - maybe all we want to do is map LocalMOOS->UDP_Out 00415 CMOOSCommunity * pLocalCommunity = GetOrMakeCommunity(m_sLocalCommunity); 00416 00417 if(pLocalCommunity!=NULL && !pLocalCommunity->IsMOOSClientRunning()) 00418 { 00419 //make a connection to the local DB 00420 pLocalCommunity->InitialiseMOOSClient(sLocalHost, 00421 atoi(sLocalPort.c_str()), 00422 m_MissionReader.GetAppName(), 00423 m_nBridgeFrequency); 00424 } 00425 00426 return true; 00427 } 00428 00429 00430 00431 CMOOSCommunity * CMOOSBridge::GetOrMakeCommunity(const string &sCommunity) 00432 { 00433 CMOOSCommunity* pCommunity = NULL; 00434 COMMUNITY_MAP::iterator p = m_Communities.find(sCommunity); 00435 if(p==m_Communities.end()) 00436 { 00437 pCommunity = new CMOOSCommunity; 00438 pCommunity->Initialise(sCommunity); 00439 m_Communities[sCommunity] = pCommunity; 00440 } 00441 else 00442 { 00443 pCommunity = p->second; 00444 } 00445 00446 return pCommunity; 00447 }