MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Essentials/pMOOSBridge/MOOSBridge.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines