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 #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