MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Core/MOOSLIB/MOOSCommClient.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 #ifdef _WIN32
00031 #pragma warning(disable : 4786)
00032 #pragma warning(disable : 4503)
00033 #endif
00034 
00035 
00036 // MOOSCommClient.cpp: implementation of the CMOOSCommClient class.
00037 //
00039 #ifdef _WIN32
00040     #include <winsock2.h>
00041     #include "windows.h"
00042     #include "winbase.h"
00043     #include "winnt.h"
00044     #define isnan _isnan
00045 #else
00046     #include <pthread.h>
00047 #endif
00048 
00049 #include <cmath>
00050 #include <string>
00051 #include <set>
00052 #include <limits>
00053 #include <iostream>
00054 #include <iomanip>
00055 #include <cassert>
00056 
00057 #include <MOOSGenLib/MOOSGenLib.h>
00058 #include "XPCTcpSocket.h"
00059 #include "MOOSCommClient.h"
00060 #include "MOOSCommPkt.h"
00061 #include "MOOSGlobalHelper.h"
00062 #include "MOOSException.h"
00063 #include "MOOSSkewFilter.h"
00064 
00065 
00066 
00067 #define MOOS_SERVER_REQUEST_ID  -2
00068 
00069 
00070 using namespace std;
00071 
00072 
00074 // Construction/Destruction
00076 
00077 
00078 
00079 
00080 /*file scope function to redirect thread work to a particular instance of CMOOSCommClient */
00081 bool ClientLoopProc( void * pParameter)
00082 {
00083         CMOOSCommClient* pMe =  (CMOOSCommClient*)pParameter;    
00084         return pMe->ClientLoop();       
00085 }
00086 
00087 CMOOSCommClient::CMOOSCommClient()
00088 {
00089     m_bClientLoopIsRunning = false;
00090 
00091         m_pConnectCallBackParam = NULL;
00092         m_pfnConnectCallBack = NULL;
00093 
00094         m_pfnDisconnectCallBack = NULL;
00095         m_pDisconnectCallBackParam = NULL;
00096     
00097     m_pfnMailCallBack = NULL;
00098         m_pSocket = NULL;
00099 
00100         m_nOutPendingLimit = OUTBOX_PENDING_LIMIT;
00101         m_nInPendingLimit = INBOX_PENDING_LIMIT;
00102         m_bConnected = false;
00103         m_nFundamentalFreq = CLIENT_DEFAULT_FUNDAMENTAL_FREQ;
00104         m_nNextMsgID=0;
00105         m_bFakeSource = false;
00106     m_bQuiet= false;
00107     
00108     //by default this client will adjust the local time skew
00109     //by using time information sent by the CommServer sitting
00110     //at the other end of this conenection.
00111     m_bDoLocalTimeCorrection = true;
00112         
00113         m_bMailPresent = false;
00114     
00115     SetVerboseDebug(false);
00116 
00117         SocketsInit();
00118 
00119 }
00120 
00121 CMOOSCommClient::~CMOOSCommClient()
00122 {
00123         Close();
00124 }
00125 
00126 bool CMOOSCommClient::Run(const char *sServer, long lPort, const char * sMyName, unsigned int nFundamentalFrequency)
00127 {
00128         m_bQuit = false;
00129 
00130         //do advert
00131         DoBanner();
00132 
00133         //who are we going to be talking to?
00134         m_sDBHost = sServer;
00135 
00136         //and on what port are they listening
00137         m_lPort = lPort;
00138 
00139         //and what are we called?
00140         m_sMyName = sMyName;
00141 
00142         if(m_pfnConnectCallBack==NULL)
00143         {
00144                 MOOSTrace("Warning no connect call back has been specified\n");
00145         }
00146 
00147         m_nFundamentalFreq=nFundamentalFrequency;
00148 
00149         if(m_nFundamentalFreq>CLIENT_MAX_FUNDAMENTAL_FREQ)
00150         {
00151                 MOOSTrace("Setting Fundamental Freq to maximum value of %d Hz\n",CLIENT_MAX_FUNDAMENTAL_FREQ);
00152                 m_nFundamentalFreq=CLIENT_MAX_FUNDAMENTAL_FREQ;
00153         }
00154         else
00155         {
00156                 //MOOSTrace("Comms Running @ %d Hz\n",m_nFundamentalFreq);
00157         }
00158 
00159 
00160         StartThreads();
00161 
00162         return true;
00163 }
00164 
00165 bool CMOOSCommClient::SetCommsTick(int nCommTick)
00166 {
00167     if(nCommTick>CLIENT_MAX_FUNDAMENTAL_FREQ)
00168         {
00169                 MOOSTrace("Setting Fundamental Freq to maximum value of %d Hz\n",CLIENT_MAX_FUNDAMENTAL_FREQ);
00170                 m_nFundamentalFreq=CLIENT_MAX_FUNDAMENTAL_FREQ;
00171         return false;
00172         }
00173     else
00174     {
00175         MOOSTrace("setting comms tick\n");
00176         m_nFundamentalFreq = (int)nCommTick;
00177         if(m_nFundamentalFreq==0)//catch a stupid setting
00178             m_nFundamentalFreq = 1;
00179         return true;
00180     }
00181     
00182 }
00183 
00184 
00185 //void CMOOSCommClient::SetOnMailtCallBack(bool (__cdecl *pfn)( void * pMailtParam), void * pMailParam)
00186 void CMOOSCommClient::SetOnMailCallBack(bool (*pfn)( void * pMailParam), void * pMailParam)
00187 {
00188         m_pfnMailCallBack = pfn;
00189         m_pMailCallBackParam = pMailParam;
00190 }
00191 
00192 bool CMOOSCommClient::HasMailCallBack()
00193 {
00194     return m_pfnMailCallBack!=NULL;
00195 }
00196 
00197 
00198 //void CMOOSCommClient::SetOnConnectCallBack(bool (__cdecl *pfn)( void * pConnectParam), void * pConnectParam)
00199 void CMOOSCommClient::SetOnConnectCallBack(bool (*pfn)( void * pConnectParam), void * pConnectParam)
00200 {
00201         m_pfnConnectCallBack = pfn;
00202         m_pConnectCallBackParam = pConnectParam;
00203 }
00204 
00205 //void CMOOSCommClient::SetOnDisconnectCallBack(bool (__cdecl *pfn)( void * pConnectParam), void * pParam)
00206 void CMOOSCommClient::SetOnDisconnectCallBack(bool ( *pfn)( void * pConnectParam), void * pParam)
00207 {
00208         m_pfnDisconnectCallBack = pfn;
00209         m_pDisconnectCallBackParam = pParam;
00210 }
00211 
00212 
00213 bool CMOOSCommClient::ClientLoop()
00214 {
00215     m_bClientLoopIsRunning = true;
00216         //MOOSTrace("ClientLoop() Begins\n");s
00217     double dfTDebug = MOOSLocalTime();
00218         while(!m_bQuit)
00219         {
00220                 //this is the connect loop...
00221                 m_pSocket = new XPCTcpSocket(m_lPort);
00222 
00223                 if(ConnectToServer())
00224                 {
00225 
00226                         while(!m_bQuit)
00227                         {
00228                 
00229                 if(m_bVerboseDebug)
00230                 {
00231                                         MOOSTrace("COMMSCLIENT DEBUG: Tick period %f ms (should be %d ms)\n",MOOSLocalTime()-dfTDebug,(int)(1000.0/m_nFundamentalFreq));
00232                     dfTDebug = MOOSLocalTime();
00233                 }
00234                                    
00235                                 if(!DoClientWork())
00236                                         break;
00237                 
00238                 if(m_bVerboseDebug)
00239                     MOOSTrace("COMMSCLIENT DEBUG: DoClientWork takes %fs\n",MOOSLocalTime()-dfTDebug);
00240 
00241                                 //wait a while before contacting server again;
00242                 if(m_nFundamentalFreq==0)
00243                     m_nFundamentalFreq=1;
00244                 
00245                                 MOOSPause((int)(1000.0/m_nFundamentalFreq));
00246 
00247                         }
00248                 }
00249                 //wait one second before try to connect again
00250                 MOOSPause(1000);
00251         }
00252 
00253         //clean up on exit....
00254         if(m_pSocket!=NULL)
00255         {
00256                 if(m_pSocket)
00257                         delete m_pSocket;
00258                 m_pSocket = NULL;
00259         }
00260 
00261     if(m_bQuiet)
00262         MOOSTrace("CMOOSCommClient::ClientLoop() quits\n");
00263 
00264         m_bConnected = false;
00265 
00266     m_bClientLoopIsRunning = false;
00267 
00268         return true;
00269 }
00270 
00271 
00272 bool CMOOSCommClient::DoClientWork()
00273 {
00274         //this is the IO Loop
00275         try
00276         {
00277 
00278                 //note the symmetry here... a warm feeling
00279 
00280                 CMOOSCommPkt PktTx,PktRx;
00281                 
00282         
00283         bool bNullPacket  = false;
00284 
00285                 m_OutLock.Lock();         
00286                 {
00287                         //if nothing to send we send a NULL packet
00288                         //just to tick things over..
00289                         if(m_OutBox.empty())
00290                         {
00291                                 //default msg is MOOS_NULL_MSG
00292                                 CMOOSMsg Msg;
00293                                 Msg.m_sSrc = m_sMyName;
00294                                 m_OutBox.push_front(Msg);
00295                 bNullPacket = true;
00296                         }
00297 
00298 
00299                         //convert our out box to a single packet
00300                         try 
00301                         {
00302                                 PktTx.Serialize(m_OutBox,true);
00303                                 
00304                         }
00305                         catch (CMOOSException e) 
00306                         {
00307                                 //clear the outbox
00308                                 m_OutBox.clear();
00309                                 m_OutLock.UnLock();
00310                                 throw CMOOSException("Serialisation Failed - this must be a lot of mail..."); 
00311                         }
00312 
00313                         //clear the outbox
00314                         m_OutBox.clear();
00315 
00316 
00317                 }
00318                 m_OutLock.UnLock();
00319                     
00320                 double dfLocalPktTxTime = MOOSLocalTime();
00321 
00322         if(m_bVerboseDebug)
00323         {
00324             MOOSTrace("COMMSERVER DEBUG: instigated call in to DB at %f\n",dfLocalPktTxTime);
00325         }
00326 
00327         SendPkt(m_pSocket,PktTx);
00328                 ReadPkt(m_pSocket,PktRx);
00329                 
00330 #ifdef DEBUG_PROTOCOL_COMPRESSION
00331                 MOOSTrace("Outgoing Compression = %.3f\n",PktTx.GetCompression());
00332                 MOOSTrace("Incoming Compression = %.3f\n",PktRx.GetCompression());
00333 #endif
00334 
00335                 //quick! grab this time
00336                 double dfLocalPktRxTime = MOOSLocalTime();
00337         
00338         if(m_bVerboseDebug)
00339         {
00340             MOOSTrace("COMMSERVER DEBUG: completed call to DB after %f s\n",dfLocalPktRxTime-dfLocalPktRxTime);
00341         }
00342                  
00343 
00344 
00345                 m_InLock.Lock();
00346                 {
00347                         if(m_InBox.size()>m_nInPendingLimit)
00348                         {
00349                                 MOOSTrace("Too many unread incoming messages [%d] : purging\n",m_InBox.size());
00350                                 MOOSTrace("The user must read mail occasionally");
00351                                 m_InBox.clear();
00352                         }
00353 
00354                         //convert reply into a list of mesasges :-)
00355                         //but no NULL messages
00356                         //we ask serialise also to return the DB time
00357                         //by looking in the first NULL_MSG in the packet
00358                         double dfServerPktTxTime=numeric_limits<double>::quiet_NaN();
00359 
00360                         //extract...
00361                         PktRx.Serialize(m_InBox,false,true,&dfServerPktTxTime);
00362 
00363                         //did you manage to grab the DB time while you were there?
00364                         if(m_bDoLocalTimeCorrection && !isnan(dfServerPktTxTime))
00365             {
00366                                 UpdateMOOSSkew(dfLocalPktTxTime, dfServerPktTxTime, dfLocalPktRxTime);
00367             }
00368             
00369        
00370                         m_bMailPresent = true;
00371                 }
00372                 m_InLock.UnLock();
00373 
00374         if(m_pfnMailCallBack!=NULL && m_bMailPresent)
00375         {
00376             bool bUserResult = (*m_pfnMailCallBack)(m_pMailCallBackParam);
00377             if(!bUserResult)
00378                 MOOSTrace("user mail callback returned false..is all ok?\n");
00379         }
00380 
00381         
00382         
00383         }
00384         catch(CMOOSException e)
00385         {
00386                 MOOSTrace("Exception in ClientLoop() : %s\n",e.m_sReason);
00387                 OnCloseConnection();
00388                 return false;//jump out to connect loop....                             
00389         }
00390 
00391         return true;
00392 }
00393 
00394 
00395 bool CMOOSCommClient::StartThreads()
00396 {
00397         m_bQuit = false;
00398     if(!m_ClientThread.Initialise(ClientLoopProc,this))
00399         return false;
00400     if(!m_ClientThread.Start())
00401         return false;
00402 
00403         return true;
00404 }
00405 
00406 bool CMOOSCommClient::ConnectToServer()
00407 {
00408         if(IsConnected())
00409         {
00410                 MOOSTrace("attempt to connect to server whilst already connected...\n");
00411                 return true;
00412         }
00413 
00414         int nAttempt=0;
00415 
00416     if(!m_bQuiet)
00417             MOOSTrace("\n---------------MOOS CONNECT-----------------------\n");
00418 
00419 
00420         while(!m_bQuit)
00421         {
00422         if(!m_bQuiet)
00423                     MOOSTrace("  contacting a MOOS server %s:%d -  try %.5d ",m_sDBHost.c_str(),m_lPort,++nAttempt);
00424 
00425                 try
00426                 {
00427                         m_pSocket->vConnect(m_sDBHost.c_str());
00428                         break;
00429                 }
00430                 catch(XPCException e)
00431                 {
00432                         //connect failed....
00433                     UNUSED_PARAMETER(e);
00434 
00435                         if(m_pSocket)
00436                                 delete m_pSocket;
00437 
00438                         m_pSocket = new XPCTcpSocket(m_lPort);
00439 
00440                         MOOSPause(100);
00441                         MOOSTrace("\r");
00442                 }
00443         }
00444 
00445         if(m_bQuit)
00446         {
00447                 MOOSTrace("ConnectToServer returns early\n");
00448                 return false;
00449         }
00450 
00451     if(!m_bQuiet)
00452             MOOSTrace("\n  Contact Made\n");
00453 
00454 
00455         if(HandShake())
00456         {
00457                 //suggestion to move this to here accpted by PMN on 21st Jan 2009
00458         //we must be connected for user callback to work..
00459         m_bConnected = true;
00460 
00461         if(m_pfnConnectCallBack!=NULL)
00462                 {
00463 
00464 
00465                         if(!m_bQuiet)
00466                 MOOSTrace("  Invoking User OnConnect() callback...");
00467 
00468                         //invoke user defined callback
00469                         bool bUserResult = (*m_pfnConnectCallBack)(m_pConnectCallBackParam);
00470                         if(bUserResult)
00471                         {
00472                         if(!m_bQuiet)
00473                                 MOOSTrace("ok\n");
00474                         }
00475                         else
00476                         {
00477                         if(!m_bQuiet)
00478                                 MOOSTrace("fail\n");
00479                 else
00480                     MOOSTrace("failed User OnConnect() callback\n");
00481                         }
00482 
00483                 }
00484         }
00485         else
00486         {
00487                 m_bQuit = true;
00488 
00489                 if(m_pSocket)
00490                         delete m_pSocket;
00491 
00492                 m_pSocket = new XPCTcpSocket(m_lPort);
00493                 return false;
00494         }
00495 
00496     if(!m_bQuiet)
00497         MOOSTrace("--------------------------------------------------\n\n");
00498         return true;
00499 }
00500 
00503 bool CMOOSCommClient::Post(CMOOSMsg &Msg)
00504 {
00505         if(!IsConnected())
00506                 return false;
00507 
00508         m_OutLock.Lock();
00509 
00510         //stuff our name in here  - prevent client from having to worry about
00511         //it...
00512         if(!m_bFakeSource )
00513         {
00514                 Msg.m_sSrc = m_sMyName;
00515         }
00516         else
00517         {
00518                 if(!Msg.IsType(MOOS_NOTIFY))
00519                 {
00520                         Msg.m_sSrc = m_sMyName;
00521                 }
00522         }
00523         
00524 
00525         if(Msg.IsType(MOOS_SERVER_REQUEST))
00526         {
00527                 Msg.m_nID=MOOS_SERVER_REQUEST_ID;       
00528         }
00529         else 
00530         {
00531                 //set up Message ID;
00532                 Msg.m_nID=m_nNextMsgID++;
00533         }
00534 
00535 
00536         m_OutBox.push_front(Msg);
00537 
00538         if(m_OutBox.size()>m_nOutPendingLimit)
00539         {       
00540                 MOOSTrace("\nThe outbox is very full. This is suspicious and dangerous.\n");
00541                 MOOSTrace("\nRemoving old unsent messages as new ones are added\n");
00542                 //remove oldest message...
00543                 m_OutBox.pop_back();
00544         }
00545 
00546         m_OutLock.UnLock();
00547 
00548         return true;
00549 
00550 }
00551 
00554 bool CMOOSCommClient::Fetch(MOOSMSG_LIST &MsgList)
00555 {
00556 
00557         if(!m_bMailPresent)
00558                 return false;
00559 
00560         MsgList.clear();
00561 
00562         m_InLock.Lock();
00563 
00564         MOOSMSG_LIST::iterator p;
00565 
00566         for(p = m_InBox.begin();p!=m_InBox.end();p++)
00567         {
00568                 CMOOSMsg & rMsg = *p;
00569                 if(!rMsg.IsType(MOOS_NULL_MSG))
00570                 {
00571                         //only give client non NULL Msgs
00572 
00573                         MsgList.push_front(rMsg);
00574                 }
00575         }
00576 
00577         //remove all elements
00578         m_InBox.clear();
00579 
00580         m_bMailPresent = false;
00581 
00582         m_InLock.UnLock();
00583 
00584         return !MsgList.empty();
00585 }
00586 
00587 bool CMOOSCommClient::HandShake()
00588 {
00589         try
00590         {
00591         if(!m_bQuiet)
00592                     MOOSTrace("  Handshaking as \"%s\"\n",m_sMyName.c_str());
00593 
00594         if(m_bDoLocalTimeCorrection)
00595                     SetMOOSSkew(0);
00596                 
00597                 //announce the protocl we will be talking...
00598                 m_pSocket->iSendMessage((void*)MOOS_PROTOCOL_STRING, MOOS_PROTOCOL_STRING_BUFFER_SIZE);
00599 
00600                 //a little bit of handshaking..we need to say who we are
00601                 CMOOSMsg Msg(MOOS_DATA,"",(char *)m_sMyName.c_str());
00602 
00603                 SendMsg(m_pSocket,Msg);
00604 
00605                 CMOOSMsg WelcomeMsg;
00606 
00607                 ReadMsg(m_pSocket,WelcomeMsg);
00608 
00609                 if(WelcomeMsg.IsType(MOOS_POISON))
00610                 {
00611             if(!m_bQuiet)
00612             {
00613                             MOOSTrace("..failed\n");
00614                             MOOSTrace("->   MOOS Server Poisoned me....\n");
00615                             MOOSTrace("->   What I did wrong was :\"%s\"",WelcomeMsg.m_sVal.c_str());
00616             }
00617             else
00618             {
00619                 MOOSTrace("Breaking a vow of silence - handshaking failed (poisoned)\n");
00620             }
00621                         return false;
00622                 }
00623                 else
00624                 {
00625                         //read our skew
00626                if(!m_bQuiet)
00627                 MOOSTrace("  Handshaking Complete\n");
00628 
00629                         double dfSkew = WelcomeMsg.m_dfVal;
00630             if(m_bDoLocalTimeCorrection)
00631                             SetMOOSSkew(dfSkew);
00632 
00633 
00634                 }
00635         }
00636         catch(CMOOSException e)
00637         {
00638                 MOOSTrace("Exception in hand shaking : %s",e.m_sReason);
00639                 return false;
00640         }
00641         return true;
00642 
00643 }
00644 
00645 bool CMOOSCommClient::IsConnected()
00646 {
00647         return m_bConnected;
00648 }
00649 
00650 bool CMOOSCommClient::OnCloseConnection()
00651 {
00652         if(!m_bQuiet)
00653                 MOOSTrace("closing connection...");
00654         m_pSocket->vCloseSocket();
00655         if(m_pSocket)
00656                 delete m_pSocket;
00657         m_pSocket= NULL;
00658         m_bConnected = false;
00659         if(!m_bQuiet)
00660                 MOOSTrace("done\n");
00661 
00662         ClearResources();
00663 
00664         if(m_pfnDisconnectCallBack!=NULL)
00665         {
00666                 if(!m_bQuiet)
00667                         MOOSTrace("Invoking User OnDisconnect() callback...");
00668                 //invoke user defined callback
00669                 bool bUserResult = (*m_pfnDisconnectCallBack)(m_pDisconnectCallBackParam);
00670                 if(bUserResult)
00671                 {
00672                         if(!m_bQuiet)
00673                                 MOOSTrace("ok\n");
00674                 }
00675                 else
00676                 {
00677                         if(!m_bQuiet)
00678                                 MOOSTrace("returned fail\n");
00679                 }
00680 
00681         }
00682 
00683 
00684         return true;
00685 }
00686 
00687 void CMOOSCommClient::DoBanner()
00688 {
00689     if(m_bQuiet)
00690         return ;
00691 
00692         MOOSTrace("****************************************************\n");
00693         MOOSTrace("*                                                  *\n");
00694         MOOSTrace("*       This is MOOS Client                        *\n");
00695         MOOSTrace("*       c. P Newman 2001                           *\n");
00696         MOOSTrace("*                                                  *\n");
00697 #ifdef _WIN32
00698         //MOOSTrace("*       built on %s\n",__TIMESTAMP__);             
00699 #endif
00700         MOOSTrace("****************************************************\n");
00701 
00702 }
00703 
00704 bool CMOOSCommClient::UnRegister(const string &sVar)
00705 {
00706         if(m_Registered.find(sVar)==m_Registered.end() || m_Registered.empty())
00707         {
00708                 return true;
00709         }
00710 
00711         CMOOSMsg MsgUR(MOOS_UNREGISTER,sVar.c_str(),0.0);
00712         if(Post(MsgUR))
00713         {
00714                 m_Registered.erase(sVar);
00715                 return true;
00716         }
00717         else
00718         {
00719                 return false;
00720         }
00721 
00722 }
00723 
00724 bool CMOOSCommClient::Register(const string &sVar, double dfInterval)
00725 {
00726         if(sVar.empty())
00727                 return MOOSFail("\n ** WARNING ** Cannot register for \"\" (empty string)\n");
00728 
00729         if(m_Registered.find(sVar)==m_Registered.end() || m_Registered.empty())
00730         {
00731                 CMOOSMsg MsgR(MOOS_REGISTER,sVar.c_str(),dfInterval);
00732                 bool bSuccess =  Post(MsgR);
00733                 if(bSuccess)
00734                 {
00735                         m_Registered.insert(sVar);
00736                 }
00737                 return bSuccess;
00738         }
00739         else
00740         {
00741                 return false;
00742         }
00743 }
00744 
00745 
00746 bool CMOOSCommClient::IsRegisteredFor(const std::string & sVariable)
00747 {
00748     return !m_Registered.empty() && m_Registered.find(sVariable)!=m_Registered.end();
00749 }
00750 
00751 bool CMOOSCommClient::Notify(const string &sVar, double dfVal, double dfTime)
00752 {
00753         CMOOSMsg Msg(MOOS_NOTIFY,sVar.c_str(),dfVal,dfTime);
00754 
00755         m_Published.insert(sVar);
00756 
00757         return Post(Msg);
00758 
00759 }
00760 
00761 
00762 
00763 bool CMOOSCommClient::Notify(const std::string & sVar,double dfVal, const std::string & sSrcAux,double dfTime)
00764 {
00765         CMOOSMsg Msg(MOOS_NOTIFY,sVar.c_str(),dfVal,dfTime);
00766 
00767         Msg.SetSourceAux(sSrcAux);
00768         
00769         m_Published.insert(sVar);
00770         
00771         return Post(Msg);
00772 }
00773 
00774 
00775 
00776 bool CMOOSCommClient::Notify(const string &sVar, const string & sVal, double dfTime)
00777 {
00778         CMOOSMsg Msg(MOOS_NOTIFY,sVar.c_str(),sVal.c_str(),dfTime);
00779 
00780         m_Published.insert(sVar);
00781 
00782         return Post(Msg);
00783 }
00784 
00785 
00786 
00787 bool CMOOSCommClient::Notify(const std::string &sVar, const std::string & sVal, const std::string & sSrcAux, double dfTime)
00788 {
00789         CMOOSMsg Msg(MOOS_NOTIFY,sVar.c_str(),sVal.c_str(),dfTime);
00790         
00791         Msg.SetSourceAux(sSrcAux);
00792         
00793         m_Published.insert(sVar);
00794         
00795         return Post(Msg);
00796 }
00797 
00798 bool CMOOSCommClient::Notify(const string &sVar, void * pData,unsigned int nSize, double dfTime)
00799 {
00800         std::string BinaryPayload((char*)pData,nSize);
00801         
00802         CMOOSMsg Msg(MOOS_NOTIFY,sVar,BinaryPayload,dfTime);
00803         Msg.MarkAsBinary();
00804         
00805         m_Published.insert(sVar);
00806         
00807         return Post(Msg);
00808         
00809 }
00810 
00811 
00812 bool CMOOSCommClient::Notify(const string &sVar, void * pData,unsigned int nSize, const std::string & sSrcAux,double dfTime)
00813 {
00814         std::string BinaryPayload((char*)pData,nSize);
00815         
00816         CMOOSMsg Msg(MOOS_NOTIFY,sVar,BinaryPayload,dfTime);
00817         Msg.MarkAsBinary();
00818         
00819         Msg.SetSourceAux(sSrcAux);
00820         
00821         m_Published.insert(sVar);
00822         
00823         return Post(Msg);
00824         
00825 }
00826 
00827 
00828 
00829 
00830 bool CMOOSCommClient::ServerRequest(const string &sWhat,MOOSMSG_LIST  & MsgList, double dfTimeOut, bool bClear)
00831 {
00832     if(!IsConnected())
00833         return false;
00834     
00835         CMOOSMsg Msg(MOOS_SERVER_REQUEST,sWhat.c_str(),"");
00836         Post(Msg);
00837         
00838         if(Msg.m_nID != MOOS_SERVER_REQUEST_ID)
00839         {
00840                 return MOOSFail("Logical Error in ::ServerRequest");
00841         }
00842 
00843         int nSleep = 100;
00844 
00845         double dfWaited = 0.0;
00846 
00847         while(dfWaited<dfTimeOut)
00848         {
00849                 if (Peek(MsgList, MOOS_SERVER_REQUEST_ID, bClear)) 
00850                 {
00851                         //OK we have our reply...
00852                         return true;            
00853                 }
00854                 else
00855                 {
00856                         MOOSPause(nSleep);
00857                         dfWaited+=((double)nSleep)/1000.0;
00858 
00859                 }
00860         }
00861 
00862         return false;
00863 }
00864 
00865 bool CMOOSCommClient::Peek(MOOSMSG_LIST & MsgList, int nIDRequired,bool bClear)
00866 {
00867         MsgList.clear();
00868 
00869         m_InLock.Lock();
00870 
00871         MOOSMSG_LIST::iterator p,q;
00872 
00873         p=m_InBox.begin();
00874         while(p!=m_InBox.end())
00875         {
00876                 if(!p->IsType(MOOS_NULL_MSG))
00877                 {
00878                         //only give client non NULL Msgs
00879                         if(p->m_nID==nIDRequired)
00880                         {
00881                                 //this is the correct ID!
00882                                 MsgList.push_front(*p);
00883                                 q=p++;
00884                                 m_InBox.erase(q);
00885                                 continue;
00886                         }
00887                 }
00888                 p++;
00889         }
00890 
00891         //conditionally (ex MIT suggestion 2006) remove all elements
00892         if(bClear) 
00893                 m_InBox.clear();
00894 
00895 
00896         m_InLock.UnLock();
00897 
00898         return !MsgList.empty();
00899 }
00900 
00901 //a static helper function
00902 bool CMOOSCommClient::PeekMail(MOOSMSG_LIST &Mail,
00903                                                            const string &sKey, 
00904                                                            CMOOSMsg &Msg,
00905                                                            bool bRemove,
00906                                                            bool bFindYoungest )
00907 {
00908         MOOSMSG_LIST::iterator p;
00909         MOOSMSG_LIST::iterator q =Mail.end();
00910 
00911         double dfYoungest = -1;
00912 
00913         for(p = Mail.begin();p!=Mail.end();p++)
00914         {
00915                 if(p->m_sKey==sKey)
00916                 {
00917                         //might want to consider more than one msg....
00918 
00919                         if(bFindYoungest)
00920                         {
00921                                 if(p->m_dfTime>dfYoungest)
00922                                 {
00923                                         dfYoungest=p->m_dfTime;
00924                                         q = p;
00925                                 }
00926                         }
00927                         else
00928                         {
00929                                 //simply take first
00930                                 q=p;
00931                                 break;
00932                         }
00933 
00934                 }
00935         }
00936 
00937         if(q!=Mail.end())
00938         {
00939                 Msg=*q;
00940 
00941                 if(bRemove)
00942                 {
00943                         //Mail.erase(p);
00944                         Mail.erase(q);
00945                 }
00946                 return true;
00947 
00948         }
00949 
00950         return false;
00951 }
00952 
00953 
00954 
00955 bool CMOOSCommClient::PeekAndCheckMail(MOOSMSG_LIST &Mail, const std::string &sKey, CMOOSMsg &Msg,bool bErase , bool bFindYoungest)
00956 {
00957     if(PeekMail(Mail,sKey,Msg,bErase,bFindYoungest))
00958         return(!Msg.IsSkewed(MOOSTime()-5.0));
00959     else
00960         return false;
00961 }
00962 
00963 bool CMOOSCommClient::Close(bool bNice )
00964 {
00965 
00966         m_bQuit = true;
00967         
00968     m_ClientThread.Stop();
00969     
00970     int i = 0;
00971 
00972         //while(m_bConnected )
00973         while(m_bClientLoopIsRunning)
00974         {
00975                 MOOSPause(100);
00976 
00977                 if(++i>100)
00978                 {
00979                         MOOSTrace("failed to close MOOSClient object! Most Strange.\n");
00980                         return false;
00981                 }
00982         }
00983 
00984         ClearResources();
00985 
00986         return true;
00987 }
00988 
00989 bool CMOOSCommClient::FakeSource(bool bFake)
00990 {
00991         m_bFakeSource = bFake;
00992         return true;
00993 }
00994 
00995 bool CMOOSCommClient::ClearResources()
00996 {
00997         if(!m_bQuiet)
00998                 MOOSTrace("purging out box...");
00999         m_OutLock.Lock();
01000         m_OutBox.clear();
01001         m_OutLock.UnLock();
01002         if(!m_bQuiet)
01003                 MOOSTrace("done\n");
01004 
01005         if(!m_bQuiet)
01006                 MOOSTrace("purging in box...");
01007         m_InLock.Lock();
01008         m_InBox.clear();
01009         m_InLock.UnLock();
01010         if(!m_bQuiet)
01011         MOOSTrace("done\n");
01012 
01013         if(!m_bQuiet)
01014                 MOOSTrace("clearing registered set...");
01015         m_Registered.clear();
01016         if(!m_bQuiet)
01017                 MOOSTrace("done\n");
01018 
01019         return true;
01020 
01021 }
01022 
01023 string CMOOSCommClient::GetDescription()
01024 {
01025     //pmn makes this more of a standard thing in May 2009  - use of : instead of @
01026         return MOOSFormat("%s:%d",m_sDBHost.c_str(),m_lPort);
01027 }
01028 
01029 string CMOOSCommClient::GetLocalIPAddress()
01030 {
01031         char Name[255];
01032         if(gethostname(Name,sizeof(Name))!=0)
01033         {
01034                 MOOSTrace("Error getting host name\n");
01035                 return "unknown";
01036         }
01037         return std::string(Name);
01038 }
01039 
01040 
01041 //std::auto_ptr<std::ofstream> SkewLog(NULL);
01042 
01043 bool CMOOSCommClient::UpdateMOOSSkew(double dfRqTime, double dfTxTime, double dfRxTime)
01044 {
01045         double dfOldSkew = GetMOOSSkew();
01046 
01047         // This function needs to be provided MOOSLocal time stamps!
01048 
01049         //back out correction which has already been made..
01050         //dfRqTime-=dfOldSkew;
01051         //dfRxTime-=dfOldSkew;
01052 
01053 #ifdef MOOS_DETECT_CLOCK_DRIFT
01054 
01055         // This is an experimental and unfinished feature.  It tracks the drift between
01056         // clocks on client and server, in order to provide highly accurate time stamps
01057         // at the client, which are within about 0.1ms of the server time.
01058         //
01059         // In its current implementation, the filter begins to suffer from numerical
01060         // issues after around 3 or 4 hours of use.  This is known and expected behaviour
01061         // and will be fixed soon.
01062         //
01063         // arh 30/03/2009
01064 
01065         if (!m_pSkewFilter.get())
01066         {
01067                 // Make a fresh skew filter
01068                 //m_pSkewFilter = std::auto_ptr<MOOS::CMOOSSkewFilter>(new MOOS::CMOOSConditionedSkewFilter);
01069                 m_pSkewFilter = std::auto_ptr<MOOS::CMOOSSkewFilter>(new MOOS::CMOOSSkewFilter);
01070                 if (!m_pSkewFilter.get()) return false;
01071         }
01072 
01073         MOOS::CMOOSSkewFilter::tSkewInfo skewinfo;
01074         double dfNewSkew = m_pSkewFilter->Update(dfRqTime, dfTxTime, dfRxTime, &skewinfo);
01075 
01076 #else // MOOS_DETECT_CLOCK_DRIFT
01077         
01078         double dfMeasuredSkew = dfTxTime-dfRxTime;
01079 
01080         double dfNewSkew;
01081         if(dfOldSkew!=0.0)
01082         {
01083                 dfNewSkew = 0.9*dfOldSkew+0.1*dfMeasuredSkew;   
01084                 //MOOSTrace("Tx Time (@DB) = %.4f Localtime (@localhost) = %.4f Skew = %.4f smoothed skew = %.5f seconds\n",dfTxTime,HPMOOSTime(),dfMeasuredSkew,dfNewSkew);
01085         }
01086         else
01087         {
01088                 dfNewSkew = dfMeasuredSkew;
01089         }
01090 
01091 #endif // MOOS_DETECT_CLOCK_DRIFT
01092 
01093 /*
01094         if (SkewLog.get())
01095         {
01096             SkewLog->setf(std::ios::fixed);
01097             (*SkewLog) << 
01098                 "RQ=" << setprecision(9) << dfRqTime << "," <<
01099                 "TX=" << setprecision(9) << dfTxTime << "," <<
01100                 "RX=" << setprecision(9) << dfRxTime << "," <<
01101 #ifdef MOOS_DETECT_CLOCK_DRIFT
01102                 "m=" << setprecision(9) << skewinfo.m << "," <<
01103                 "c=" << setprecision(9) << skewinfo.c << "," <<
01104                 "LB=" << setprecision(9) << skewinfo.LB << "," <<
01105                 "UB=" << setprecision(9) << skewinfo.UB << "," <<
01106                 "envLB=" << setprecision(9) << skewinfo.envLB << "," <<
01107                 "envUB=" << setprecision(9) << skewinfo.envUB << "," <<
01108                 "envEst=" << setprecision(9) << skewinfo.envEst << "," <<
01109                 "filtEst=" << setprecision(9) << skewinfo.filtEst <<
01110 #endif // MOOS_DETECT_CLOCK_DRIFT
01111                 std::endl;              
01112         }
01113 */
01114 
01115         SetMOOSSkew(dfNewSkew);
01116 
01117         return true;
01118 }
01119 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines