# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

message_recorder.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "stdnet.h"
00027 
00028 #include "nel/net/message_recorder.h"
00029 #include "nel/net/inet_address.h"
00030 
00031 using namespace NLMISC;
00032 using namespace std;
00033 
00034 
00035 namespace NLNET {
00036 
00037 
00039 string EventToString( TNetworkEvent e )
00040 {
00041         switch ( e )
00042         {
00043         case Sending: return "SEND";
00044         case Receiving: return "RECV";
00045         case Connecting: return "CONN";
00046         case ConnFailing: return "CNFL";
00047         case Accepting: return "ACCP";
00048         case Disconnecting: return "DISC";
00049         default: nlstop; return "-ERR-";
00050         }
00051 }
00052 
00054 TNetworkEvent StringToEvent( string& s )
00055 {
00056         if ( s == "RECV" )
00057                 return Receiving;
00058         else if ( s == "SEND" )
00059                 return Sending;
00060         else if ( s == "DISC" )
00061                 return Disconnecting;
00062         else if ( s == "ACCP" )
00063                 return Accepting;
00064         else if ( s == "CONN" )
00065                 return Connecting;
00066         else if ( s == "CNFL" )
00067                 return ConnFailing;
00068         else 
00069         {
00070                 nlstop;
00071                 return Error;
00072         }
00073 }
00074 
00075 
00076 /*
00077  * Constructor
00078  */
00079 CMessageRecorder::CMessageRecorder() : _RecordAll(true)
00080 {
00081 #ifndef MESSAGES_PLAIN_TEXT
00082         nlerror( "The message recorder works only with plain text messages. Please #define MESSAGES_PLAIN_TEXT" );
00083 #endif
00084 }
00085 
00086 
00087 /*
00088  * Destructor
00089  */
00090 CMessageRecorder::~CMessageRecorder()
00091 {
00092         if ( _Filename != "" )
00093         {
00094                 nldebug( "MR:%s: End of recording", _Filename.c_str() );
00095         }
00096         stopRecord();
00097         stopReplay();
00098 }
00099 
00100 
00101 /*
00102  * Start recording
00103  */
00104 bool CMessageRecorder::startRecord( const std::string& filename, bool recordall )
00105 {
00106         _Filename = filename;
00107         _File.open( _Filename.c_str(), ios_base::out );
00108         _File << endl;
00109         _RecordAll = recordall;
00110         if ( _File.fail() )
00111         {
00112                 nlwarning( "MR: Record: Cannot open file %s", _Filename.c_str() );
00113                 return false;
00114         }
00115         else
00116         {
00117                 nldebug( "MR: Start recording into %s", _Filename.c_str() );
00118                 return true;
00119         }
00120 }
00121 
00122 
00123 /*
00124  * Same as stringFromVector() but assumes the vector contains only printable characters
00125  */
00126 /*string stringFromTextVector( const vector<uint8>& v )
00127 {
00128         string s;
00129 
00130         // Copy contents
00131         s.resize( v.size() );
00132         memcpy( &*s.begin(), &*v.begin(), v.size() );
00133 
00134         return s;
00135 }*/
00136 
00137 
00138 /*
00139  * Add a record
00140  */
00141 void CMessageRecorder::recordNext( sint64 updatecounter, TNetworkEvent event, TSockId sockid, CMessage& message )
00142 {
00143         nlassert( _File.is_open() );
00144 
00145         if ( (_RecordAll) || (event != Sending) )
00146         {
00147                 // Serial to stream
00148                 TMessageRecord rec ( event, sockid, message, updatecounter /*CTime::getLocalTime()*/ );
00149                 CMemStream stream ( false, true );
00150                 rec.serial( stream );
00151                 char c = '\0';      // end of cstring
00152                 stream.serial( c ); // added to the stream for _File << (char*)stream.buffer()
00153 
00154                 // Dump to file
00155                 nldebug( "MR:%s: Recording [%s]", _Filename.c_str(), stream.buffer() );
00156                 int len = (int)(stream.length()-2); // not the null character (and its separator) at the end of the buffer
00157                 _File << "* ";
00158                 _File <<  len; // if we put the expression directly, it makes an access violation ! Weird.
00159                 _File << " ";
00160                 _File << (char*)stream.buffer() << endl; 
00161         }
00162 }
00163 
00164 
00165 /*
00166  * Stop recording
00167  */
00168 void CMessageRecorder::stopRecord()
00169 {
00170         _File.close();
00171         _Filename = "";
00172 }
00173 
00174 
00175 /*
00176  * Start playback
00177  */
00178 bool CMessageRecorder::startReplay( const std::string& filename )
00179 {
00180         _Filename = filename;
00181         _File.open( _Filename.c_str(), ios_base::in );
00182         if ( _File.fail() )
00183         {
00184                 nlerror( "MR: Replay: Cannot open file %s", _Filename.c_str() );
00185                 return false;
00186         }
00187         else
00188         {
00189                 nldebug( "MR: Start replaying from %s", _Filename.c_str() );
00190                 return true;
00191         }
00192 }
00193 
00194 
00195 /*
00196  * Get next record (throw EStreamOverflow)
00197  */
00198 bool CMessageRecorder::loadNext( TMessageRecord& record )
00199 {
00200         // WARNING!!! This features doesn't work anymore becaues bufferAsVector() is not available with new CMemStream
00201         nlstop;
00202         return false;
00203 
00204         nlassert( _File.is_open() );
00205 
00206         // Dump from file
00207         CMemStream stream ( true, true );
00208         uint32 len;
00209         char c;
00210         _File >> c; // skip "* ";
00211         _File >> (int&)len;
00212         _File.ignore(); // skip delimiter
00213         if ( ! _File.fail() )
00214         {
00215                 _File.get( (char*)stream.bufferToFill( len+1 ), len+1, '\0' );
00216                 //stream.bufferAsVector().resize( len ); // cut end of cstring
00217                 nldebug( "MR:%s: Reading [%s]", _Filename.c_str(), stream.buffer() );
00218 
00219                 // Serial from stream
00220                 record.serial( stream ); // may throw EStreamOverflow if _File.fail()
00221         }
00222 
00223         return ! _File.fail(); // retest
00224 }
00225 
00226 
00227 /*
00228  * Get the next record (from the preloaded records, or from the file)
00229  */
00230 bool CMessageRecorder::getNext( TMessageRecord& record, sint64 updatecounter )
00231 {
00232         if ( ! _PreloadedRecords.empty() )
00233         {
00234                 if ( _PreloadedRecords.front().UpdateCounter == updatecounter )
00235                 {
00236                         // The requested record is in the preload
00237                         record = _PreloadedRecords.front();
00238                         _PreloadedRecords.pop_front();
00239                         return true;
00240                 }
00241                 else
00242                 {
00243                         // The requested record is not in the file
00244                         nlassert( updatecounter < _PreloadedRecords.front().UpdateCounter ); // not >
00245                         return false;
00246                 }
00247         }
00248         else
00249         {
00250                 if ( loadNext( record ) )
00251                 {
00252                         if ( record.UpdateCounter == updatecounter )
00253                         {
00254                                 // The requested record has been loaded
00255                                 return true;
00256                         }
00257                         else
00258                         {
00259                                 // The next loaded record is a new one
00260                                 nlassert( updatecounter < record.UpdateCounter ); // not >
00261                                 _PreloadedRecords.push_back( record ); // when we read one too far
00262                                 return false;
00263                         }
00264                 }
00265                 else
00266                 {
00267                         return false;
00268                 }
00269         }
00270 }
00271 
00272 
00273 /*
00274  * Push the received blocks for this counter into the receive queue
00275  */
00276 void CMessageRecorder::replayNextDataAvailable( sint64 updatecounter )
00277 {
00278         TMessageRecord rec( true ); // input message
00279 
00280         while ( getNext( rec, updatecounter ) )
00281         {
00282                 switch ( rec.Event )
00283                 {
00284                 case Receiving :
00285                 case Accepting :
00286                 case Disconnecting :
00287                         ReceivedMessages.push( rec );
00288                         break;
00289 
00290                 case Sending :
00291                         break;
00292 
00293                 case Connecting :
00294                 case ConnFailing :
00295                         _ConnectionAttempts.push_back( rec );
00296                         break;
00297                         
00298                 default :
00299                         nlstop;
00300                 }
00301         }
00302 }
00303 
00304 
00305 /*
00306  * Returns true and the event type if the counter of the next data is updatecounter
00307  */
00308 TNetworkEvent CMessageRecorder::checkNextOne( sint64 updatecounter )
00309 {
00310         TMessageRecord record;
00311         if ( getNext( record, updatecounter ) )
00312         {
00313                 nldebug( "MR: Check next one: %s at update %"NL_I64"u", EventToString(record.Event).c_str(), updatecounter );
00314                 return record.Event;
00315         }
00316         else
00317         {
00318                 return Error;
00319         }
00320 }
00321 
00322 
00323 /*
00324  * Get the first stored connection attempt corresponding to addr
00325  */
00326 TNetworkEvent CMessageRecorder::replayConnectionAttempt( const CInetAddress& addr )
00327 {
00328         TNetworkEvent event;
00329         deque<TMessageRecord>::iterator ipr;
00330         
00331         if ( ! _ConnectionAttempts.empty() )
00332         {
00333                 // Search in the already processed connection attempts
00334                 for ( ipr=_ConnectionAttempts.begin(); ipr!=_ConnectionAttempts.end(); ++ipr )
00335                 {
00336                         CInetAddress stored_addr;
00337                         (*ipr).Message.serial( stored_addr );
00338                         if ( stored_addr == addr )
00339                         {
00340                                 // Found
00341                                 event = (*ipr).Event;
00342                                 nldebug( "MR: Connection attempt found at update %"NL_I64"u", (*ipr).UpdateCounter );
00343                                 _ConnectionAttempts.erase( ipr );
00344                                 return event;
00345                         }
00346                 }
00347         }
00348         
00349         // Seek in the preloaded records
00350         for ( ipr=_PreloadedRecords.begin(); ipr!=_PreloadedRecords.end(); ++ipr )
00351         {
00352                 event = (*ipr).Event;
00353                 if ( (event == Connecting) || (event == ConnFailing) )
00354                 {
00355                         CInetAddress stored_addr;
00356                         (*ipr).Message.serial( stored_addr );
00357                         if ( stored_addr == addr )
00358                         {
00359                                 // Found
00360                                 nldebug( "MR: Connection attempt found at update %"NL_I64"u", (*ipr).UpdateCounter );
00361                                 _PreloadedRecords.erase( ipr );
00362                                 return event;
00363                         }
00364                 }
00365         }
00366         if ( ipr==_PreloadedRecords.end() )
00367         {
00368                 // If not found, load next records until found !
00369                 TMessageRecord rec( true );
00370                 while ( loadNext( rec ) )
00371                 {
00372                         if ( ( rec.Event == Connecting ) || ( rec.Event == ConnFailing ) )
00373                         {
00374                                 CInetAddress stored_addr;
00375                                 rec.Message.serial( stored_addr );
00376                                 if ( stored_addr == addr )
00377                                 {
00378                                         // Found
00379                                         nldebug( "MR: Connection attempt found at update %"NL_I64"u", rec.UpdateCounter );
00380                                         return rec.Event;
00381                                 }
00382                                 else
00383                                 {
00384                                         _PreloadedRecords.push_back( rec );
00385                                 }
00386                         }
00387                         else
00388                         {
00389                                 _PreloadedRecords.push_back( rec );
00390                         }
00391                 }
00392                 // Not found
00393                 nldebug( "MR: Connection attempt not found" );          
00394                 return Error;
00395         }
00396         nlstop;
00397         return Error;
00398 }
00399 
00400 
00401 /*
00402  * Stop playback
00403  */
00404 void CMessageRecorder::stopReplay()
00405 {
00406         _File.close();
00407         _Filename = "";
00408 }
00409 
00410 
00411 } // NLNET