MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Core/MOOSLIB/MOOSCommPkt.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 // MOOSCommPkt.cpp: implementation of the MOOSCommPkt class.
00031 //
00033 #ifdef _WIN32
00034     #pragma warning(disable : 4786)
00035     #pragma warning(disable : 4503)
00036 #endif
00037 
00038 
00039 #include <MOOSGenLib/MOOSGenLib.h>
00040 #include "MOOSCommPkt.h"
00041 #include "MOOSMsg.h"
00042 #include "MOOSGlobalHelper.h"
00043 #include <assert.h>
00044 #include <cstring>
00045 #include <iostream>
00046 #include "MOOSException.h"
00047 
00048 
00049 #define DEFAULT_ASSUMMED_MAX_MOOS_MSG_SIZE 40000
00050 
00051 
00052 #ifdef COMPRESSED_MOOS_PROTOCOL
00053         
00054         #define MAX_BELIEVABLE_ZLIB_COMPRESSION 256  //if we look like we are getting a compression ration of more than this then bail - there is an error.
00055 
00056         #define COMPRESSION_PACKET_SIZE_THRESHOLD 1024 //packets below this size won't be compressed.
00057 
00058         #include <zlib.h>
00059 #endif
00060 
00061 using namespace std;
00062 
00064 // Construction/Destruction
00066 
00067 CMOOSCommPkt::CMOOSCommPkt()
00068 {
00069     m_pStream = DefaultStream;
00070     m_nStreamSpace = MOOS_PKT_DEFAULT_SPACE;
00071     m_pNextData = m_pStream;
00072     m_bAllocated = false;
00073     m_nByteCount = 0;
00074     m_nMsgLen = 0;
00075         m_dfCompression = 1.0;
00076 
00077 
00078 }
00079 
00080 CMOOSCommPkt::~CMOOSCommPkt()
00081 {
00082     if(m_bAllocated)
00083     {
00084         delete [] m_pStream;
00085     }
00086 }
00087 
00088 double CMOOSCommPkt::GetCompression()
00089 {
00090         return m_dfCompression;
00091 }
00092 
00093 int CMOOSCommPkt::GetBytesRequired()
00094 {
00095     if(m_nByteCount==0)
00096     {
00097         return sizeof(int);
00098     }
00099     else
00100     {
00101         return m_nMsgLen-m_nByteCount;
00102     }
00103 }
00104 
00105 bool CMOOSCommPkt::Fill(unsigned char *InData, int nData)
00106 {
00107     
00108     if(    m_nByteCount ==0)
00109     {
00110         //here we figure out how many bytes we are expecting
00111         assert(nData==sizeof(int));
00112 
00113         memcpy((void*)(&m_nMsgLen),(void*)InData,sizeof(int));
00114 
00115         //look to swap byte order if this machine is Big End in
00116         if(!IsLittleEndian())
00117         {
00118             m_nMsgLen = SwapByteOrder<int>(m_nMsgLen);
00119         }
00120 
00121     }
00122 
00123     if(m_nByteCount+nData>=m_nStreamSpace)
00124     {
00125         InflateTo(2*(m_nStreamSpace+nData));
00126     }
00127     memcpy(m_pNextData,InData,nData);
00128     m_pNextData+=nData;
00129     m_nByteCount+=nData;
00130 
00131     return true;
00132 }
00133 
00134 
00135 int CMOOSCommPkt::GetStreamLength()
00136 {
00137     return m_nMsgLen;
00138 }
00139 
00140 
00142 bool CMOOSCommPkt::Serialize(MOOSMSG_LIST &List, bool bToStream, bool bNoNULL, double * pdfPktTime)
00143 {
00144         //note +1 is for indicator regarding compressed or not compressed
00145         unsigned int nHeaderSize = 2*sizeof(int)+1;
00146         
00147     if(bToStream)
00148     {
00149 
00150         m_nMsgLen=0;
00151         m_pNextData = m_pStream;
00152         m_nByteCount = 0;
00153 
00154         //we need to leave space at the start of the packet for total
00155         //length and number of include messages
00156                 
00157         m_pNextData+=nHeaderSize; 
00158         m_nByteCount+= nHeaderSize;
00159 
00160 
00161         //assume to start with that mesages are reasonably sized -if they aren't we'll make an adjustment
00162         unsigned int nWorkingMemoryCurrentSize = DEFAULT_ASSUMMED_MAX_MOOS_MSG_SIZE;
00163         unsigned char * pTmpBuffer =new unsigned char[nWorkingMemoryCurrentSize] ;
00164 
00165 
00166 
00167         MOOSMSG_LIST::iterator p;
00168         int nCount = 0;
00169         for(p = List.begin();p!=List.end();p++,nCount++)
00170         {
00171         
00172             unsigned int nRequiredSize = p->GetSizeInBytesWhenSerialised();
00173 
00174             if(nRequiredSize>nWorkingMemoryCurrentSize)
00175             {
00176                 //std::cerr<<"making more space "<<nWorkingMemoryCurrentSize<<" -> "<<nRequiredSize<<std::endl;
00177                 nWorkingMemoryCurrentSize = nRequiredSize;
00178                 delete [] pTmpBuffer;
00179 
00180                 pTmpBuffer = new unsigned  char [nWorkingMemoryCurrentSize];
00181             }
00182 
00183             //MOOSTrace("Sending %s \n",p->m_sKey.c_str());
00184             //int nTmpSize = MAX_MOOS_MSG_SIZE;
00185 
00186             int nCopied = (*p).Serialize(pTmpBuffer,nWorkingMemoryCurrentSize);
00187 
00188             if(nCopied !=nRequiredSize )
00189             {
00190                 std::cerr<<"bad news expected "<<nWorkingMemoryCurrentSize<<" but serialisation took "<<nCopied<<std::endl;
00191                 p->Trace();
00192             }
00193 
00194             if(nCopied!=-1)
00195             {
00196                 //now copy to our stream...
00197                 CopyToStream(pTmpBuffer,nCopied);
00198             }
00199             else
00200             {
00201                 delete [] pTmpBuffer;
00202                 return false;
00203             }
00204 
00205         }
00206 
00207         delete [] pTmpBuffer;
00208 
00209 
00210 
00211 
00212 
00213                 unsigned char bCompressed = 0;
00214 #ifdef COMPRESSED_MOOS_PROTOCOL
00215                 
00216                 //we only compress if it is worth it
00217                 if(m_nByteCount>COMPRESSION_PACKET_SIZE_THRESHOLD)
00218                 {
00219                         
00220                         unsigned long int nDataLength = m_nByteCount-nHeaderSize;
00221                         
00222                         //we require .1% extra and 12 bytes
00223                         unsigned long int nZBSize = (unsigned int) ((float)nDataLength*1.01+13);
00224                         unsigned char * ZipBuffer = new unsigned char[nZBSize];         
00225                         
00226                         int nZipResult = compress(ZipBuffer,&nZBSize,m_pStream+nHeaderSize,nDataLength);
00227                         
00228                         
00229                         switch (nZipResult) {
00230                                 case Z_OK:
00231                                         break;
00232                                 case Z_BUF_ERROR:
00233                                         throw CMOOSException("failed to compress outgoing data - looks like compression actually expanded data!");
00234                                         break;
00235                                 case Z_MEM_ERROR:
00236                                         throw CMOOSException("zlib memory error!");
00237                                         break;
00238                                 default:
00239                                         break;
00240                         }
00241                         
00242                         //MOOSTrace("Compressed out going buffer is %d bytes and original is %d\n",nZBSize,nDataLength);
00243                         
00244                         memcpy(m_pStream+nHeaderSize,ZipBuffer,nZBSize);
00245 
00246                         //maybe useful to record what compression ration we are getting
00247                         m_dfCompression = (double)m_nByteCount/nZBSize;
00248 
00249                         //now we have a new byte count                  
00250                         m_nByteCount = nZBSize+nHeaderSize;
00251                         
00252                         delete ZipBuffer;
00253                         
00254                         bCompressed = 1;
00255                         
00256                 }
00257                 
00258 #endif
00259 
00260         //finally write how many bytes we have written at the start
00261         //look for need to swap byte order if required
00262         m_pNextData = m_pStream;
00263         int nBC = IsLittleEndian() ? m_nByteCount : SwapByteOrder<int>(m_nByteCount);
00264         memcpy((void*)m_pNextData,(void*)(&nBC),sizeof(m_nByteCount));
00265         m_pNextData+=sizeof(m_nByteCount);
00266 
00267 
00268         //and then how many messages are included
00269         //look for need to swap byte order if required
00270         int nMessages = List.size();
00271         nMessages = IsLittleEndian() ? nMessages : SwapByteOrder<int>(nMessages);
00272         memcpy((void*)m_pNextData,(void*)(&nMessages),sizeof(nMessages));
00273         m_pNextData+=sizeof(nMessages);
00274                 
00275                 //and is this a compressed message or not?
00276                 *m_pNextData = bCompressed;
00277                 m_pNextData+=1;
00278 
00279 
00280     }
00281     else
00282     {
00283         
00284         m_pNextData = m_pStream;
00285         m_nMsgLen = 0;
00286         m_nByteCount = 0;
00287 
00288         //first figure out the length of the message
00289         //look to swap byte order as required
00290         memcpy((void*)(&m_nMsgLen),(void*)m_pNextData,sizeof(m_nMsgLen));
00291         m_nMsgLen = IsLittleEndian() ? m_nMsgLen : SwapByteOrder<int>(m_nMsgLen);
00292         m_pNextData+=sizeof(m_nMsgLen);
00293         m_nByteCount+=sizeof(m_nMsgLen);
00294 
00295         int nSpaceFree=m_nMsgLen - sizeof(m_nMsgLen);
00296 
00297         //now figure out how many messages are packed in this packet
00298         //look to swap byte order as required
00299         int nMessages = 0;
00300         memcpy((void*)(&nMessages),(void*)m_pNextData,sizeof(nMessages));
00301         nMessages = IsLittleEndian() ? nMessages : SwapByteOrder<int>(nMessages);
00302         m_pNextData+=sizeof(nMessages);
00303         nSpaceFree-=sizeof(nMessages);
00304         m_nByteCount+=sizeof(nMessages);
00305                 
00306                 //now account for one byet of compression indication
00307                 m_pNextData+=sizeof(unsigned char);
00308         nSpaceFree-=sizeof(unsigned char);
00309         m_nByteCount+=sizeof(unsigned char);
00310                 
00311                 
00312                 
00313 #ifdef COMPRESSED_MOOS_PROTOCOL         
00314                 unsigned char bCompressed = m_pStream[nHeaderSize-1];
00315                 //we will only have compressed if it is worth it
00316                 
00317                 //MOOSTrace("Message is %s compressed\n",bCompressed? "":"not");
00318                 if(bCompressed)
00319                 {
00320                         
00321                         unsigned long int nDataLength = m_nMsgLen-nHeaderSize;
00322                         
00323                         //we'd be surprised if we had more tha 90% compression
00324                         int nCompressionFactor = 10;
00325                         unsigned char * ZipBuffer = NULL;
00326                         unsigned long int nZBSize;
00327                         
00328                         int nZipResult = -1;
00329                         
00330                         do
00331                         {
00332                                 
00333                                 nZBSize = nCompressionFactor*nDataLength;
00334                                 
00335                                 ZipBuffer = new unsigned char[nZBSize];
00336                                 
00337                                 nZipResult = uncompress(ZipBuffer,&nZBSize,m_pStream+nHeaderSize,nDataLength);
00338                                 
00339                                 switch (nZipResult) 
00340                                 {
00341                                         case Z_MEM_ERROR:
00342                                                 throw CMOOSException("ZLIB out of memory");
00343                                                 break;
00344                                                 
00345                                         case Z_BUF_ERROR:
00346                                         {
00347                                                 //if we get here we need more space
00348                                                 delete ZipBuffer;
00349                                                 nCompressionFactor *=8;
00350                                                 
00351                                                 if(nCompressionFactor>MAX_BELIEVABLE_ZLIB_COMPRESSION)
00352                                                 {
00353                                                         //this is very suspcious
00354                                                         throw CMOOSException("error in decompressing CMOOSPkt stream");
00355                                                 }
00356                                         }
00357                                                 break;
00358                                                 
00359                                         case Z_DATA_ERROR:
00360                                                 throw CMOOSException("ZLIB received corrupted data - this is really bad news.");
00361                                                 break;
00362                                                 
00363                                                 
00364                                         default:
00365                                                 break;
00366                                 }
00367                         }while(nZipResult!=Z_OK);
00368                         
00369                         
00370                         //MOOSTrace("received %d data bytes and uncompressed them to %d  bytes\n",nDataLength,nZBSize);
00371                         
00372                         //maybe useful to record what compression ration we are getting
00373                         m_dfCompression = (double)nZBSize/nDataLength;
00374 
00375                         
00376                         //we have a new message length
00377                         m_nMsgLen = nZBSize+nHeaderSize;
00378                         
00379                         //check we have allocated enough memory
00380                         if(m_nMsgLen>m_nStreamSpace)
00381                         {
00382                                 //interesting case we are out of memory - we need some more
00383                                 InflateTo(m_nMsgLen);
00384                         }
00385                         
00386                         //copy the uncompressed data into our stream
00387                         memcpy(m_pStream+nHeaderSize,ZipBuffer,nZBSize);
00388                         
00389                         //recalculate space free
00390                         nSpaceFree= m_nMsgLen-nHeaderSize;
00391                         
00392                         //be a good citizen
00393                         delete ZipBuffer;
00394                 }
00395 #endif
00396                 
00397 
00398         for(int i = 0; i<nMessages;i++)
00399         {
00400                     
00401             CMOOSMsg Msg;
00402             int nUsed = Msg.Serialize(m_pNextData,nSpaceFree,false);
00403 
00404             if(nUsed!=-1) 
00405             {
00406                 //allows us to not store NULL messages
00407                 bool bOmit = bNoNULL && (Msg.m_cMsgType==MOOS_NULL_MSG);
00408 
00409                 if(Msg.m_cMsgType==MOOS_NULL_MSG && pdfPktTime!=NULL && i == 0 )
00410                 {
00411                     *pdfPktTime     = Msg.GetDouble();                    
00412                 }
00413 
00414                 if(!bOmit)
00415                 {
00416                     List.push_front(Msg);
00417                 }
00418 
00419 
00420                 m_pNextData+=nUsed;
00421                 m_nByteCount+=nUsed;
00422                 nSpaceFree-=nUsed;
00423 
00424             }
00425             else
00426             {
00427                 //bad news...
00428                 break;
00429             }        
00430         }
00431     }
00432 
00433     //here at the last moment we can fill in our totalm length for safe keeping
00434     m_nMsgLen = m_nByteCount;
00435 
00436     return true;
00437 }
00438 
00439 bool CMOOSCommPkt::CopyToStream(unsigned char *pData, int nBytes)
00440 {
00441     //well do we have enough space to do this?
00442     if(m_nByteCount+nBytes>=m_nStreamSpace)
00443     {
00444         //no..better inflate ourselves...
00445         InflateTo(2*(m_nStreamSpace+nBytes));
00446     }
00447 
00448     //by this point we are guaranteed enough space..
00449     //unless (new has failed which is really the end of the world and we will be dead :-(  )
00450 
00451     //copy temporary buffer to our main buffer
00452     memcpy(m_pNextData,pData,nBytes);
00453 
00454     //increment hot spot
00455     m_pNextData+=nBytes;
00456 
00457     //increment byte count
00458     m_nByteCount+=nBytes;
00459 
00460     return true;
00461 }
00462 
00463 bool CMOOSCommPkt::InflateTo(int nNewStreamSize)
00464 {
00465     //make more space then..
00466     m_nStreamSpace = nNewStreamSize;
00467 
00468     unsigned char * pNew = new unsigned char[m_nStreamSpace];
00469 
00470     if(pNew==NULL)
00471     {
00472         //absolute disaster..nothing we can do ...whole process must exit
00473         MOOSTrace("memory allocation failed in CMOOSCommPkt::CopyToStream");
00474         return false;
00475     }
00476 
00477     //copy what we have already assembled into new space
00478     memcpy(pNew,m_pStream,m_nByteCount);
00479 
00480     
00481     if(m_bAllocated)
00482     {
00483         delete [] m_pStream;
00484     }
00485     else
00486     {
00487         m_bAllocated = true;
00488     }
00489 
00490     //switch m_pStream to point to the new space;
00491     m_pStream = pNew;
00492 
00493     //and set the next data point to be m_nMsgLen bytes from start
00494     //so we will start writin after are existing stuff
00495     m_pNextData=m_pStream+m_nByteCount;
00496 
00497     return true;
00498 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines