# 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  

callback_client.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/callback_net_base.h"
00029 #include "nel/net/callback_client.h"
00030 
00031 #ifdef USE_MESSAGE_RECORDER
00032 #include "nel/net/message_recorder.h"
00033 #endif
00034 
00035 
00036 namespace NLNET {
00037 
00038 
00039 /*
00040  * Callbacks management
00041  */
00042 
00043 static void cbcMessageRecvAllAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00044 {
00045         netbase.getSIDA().ignoreAllUnknownId (false);
00046         cbnbMessageRecvAssociations (msgin, from, netbase);
00047 }
00048 
00049 
00050 static TCallbackItem ClientMessageAssociationArray[] =
00051 {
00052         { "RAA", cbcMessageRecvAllAssociations },
00053 };
00054 
00055 
00056 /*
00057  * Constructor
00058  */
00059 CCallbackClient::CCallbackClient( TRecordingState rec, const std::string& recfilename, bool recordall ) :
00060         CCallbackNetBase( rec, recfilename, recordall ), CBufClient( true, rec==Replay ), SendNextValue(0), ReceiveNextValue(0)
00061 {
00062         CBufClient::setDisconnectionCallback (_NewDisconnectionCallback, this);
00063 
00064         // add the callback needed to associate messages with id
00065         addCallbackArray (ClientMessageAssociationArray, sizeof (ClientMessageAssociationArray) / sizeof (ClientMessageAssociationArray[0]));
00066 
00067         _InputSIDA.ignoreAllUnknownId (true);
00068 
00069         _IsAServer = false;
00070         _DefaultCallback = NULL;
00071 }
00072 
00073 
00074 /*
00075  * Send a message to the remote host (pushing to its send queue)
00076  * Recorded : YES
00077  * Replayed : MAYBE
00078  */
00079 void CCallbackClient::send (const CMessage &buffer, TSockId hostid, bool log)
00080 {
00081         nlassert (hostid == InvalidSockId);     // should always be InvalidSockId on client
00082         checkThreadId ();
00083         nlassert (connected ());
00084         nlassert (buffer.length() != 0);
00085         nlassert (buffer.typeIsSet());
00086 
00087         _BytesSent += buffer.length ();
00088 
00089 //      if (log)
00090         {
00092 //              nldebug ("send message number %u", SendNextValue);
00093         }
00094 
00095         // debug features, we number all packet to be sure that they are all sent and received
00096         // \todo remove this debug feature when ok
00097         // fill the number
00098         uint32 *val = (uint32*)buffer.buffer ();
00099 #ifdef NL_BIG_ENDIAN
00100         *val = NLMISC_BSWAP32(SendNextValue);
00101 #else
00102         *val = SendNextValue;
00103 #endif
00104         SendNextValue++;
00105 
00106 
00107 #ifdef USE_MESSAGE_RECORDER
00108         if ( _MR_RecordingState != Replay )
00109         {
00110 #endif
00111 
00112                 // Send
00113                 CBufClient::send (buffer);
00114 
00115 #ifdef USE_MESSAGE_RECORDER
00116                 if ( _MR_RecordingState == Record )
00117                 {
00118                         // Record sent message
00119                         _MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );
00120                 }
00121         }
00122         else
00123         {       
00125         }
00126 #endif
00127 }
00128 
00129 /*
00130  * Force to send all data pending in the send queue.
00131  * Recorded : NO
00132  * Replayed : NO
00133  */
00134 bool CCallbackClient::flush (TSockId hostid) 
00135 {
00136         nlassert (hostid == InvalidSockId);     // should always be InvalidSockId on client
00137         checkThreadId ();
00138 
00139 #ifdef USE_MESSAGE_RECORDER
00140         if ( _MR_RecordingState != Replay )
00141         {
00142 #endif
00143 
00144                 // Flush sending (nothing to do in replay mode)
00145                 return CBufClient::flush();
00146                 
00147 #ifdef USE_MESSAGE_RECORDER
00148         }
00149         else
00150         {
00151                 return true;
00152         }
00153 #endif
00154 }
00155 
00156 
00157 /*
00158  * Updates the network (call this method evenly)
00159  * Recorded : YES (in baseUpdate())
00160  * Replayed : YES (in baseUpdate())
00161  */
00162 void CCallbackClient::update ( sint32 timeout )
00163 {
00164 //      nldebug ("L3: Client: update()");
00165 
00166         checkThreadId ();
00167 
00168         baseUpdate (timeout); // first receive
00169 
00170 #ifdef USE_MESSAGE_RECORDER
00171         if ( _MR_RecordingState != Replay )
00172         {
00173 #endif
00174 
00175                 // L1-2 Update (nothing to do in replay mode)
00176                 CBufClient::update (); // then send
00177 
00178 #ifdef USE_MESSAGE_RECORDER
00179         }
00180 #endif
00181 }
00182 
00183 
00184 /*
00185  * Returns true if there are messages to read
00186  * Recorded : NO
00187  * Replayed : YES
00188  */
00189 bool CCallbackClient::dataAvailable ()
00190 {
00191         checkThreadId ();
00192 
00193 #ifdef USE_MESSAGE_RECORDER
00194         if ( _MR_RecordingState != Replay )
00195         {
00196 #endif
00197 
00198                 // Real dataAvailable()
00199                 return CBufClient::dataAvailable (); 
00200 
00201 #ifdef USE_MESSAGE_RECORDER
00202         }
00203         else
00204         {
00205                 // Simulated dataAvailable()
00206                 return CCallbackNetBase::replayDataAvailable();
00207         }
00208 #endif
00209 }
00210 
00211 
00212 /*
00213  * Read the next message in the receive queue
00214  * Recorded : YES
00215  * Replayed : YES
00216  */
00217 void CCallbackClient::receive (CMessage &buffer, TSockId *hostid)
00218 {
00219         checkThreadId ();
00220         nlassert (connected ());
00221         *hostid = InvalidSockId;
00222 
00223 #ifdef USE_MESSAGE_RECORDER
00224         if ( _MR_RecordingState != Replay )
00225         {
00226 #endif
00227                 
00228                 // Receive
00229                 CBufClient::receive (buffer);
00230 
00231                 // debug features, we number all packet to be sure that they are all sent and received
00232                 // \todo remove this debug feature when ok
00233 #ifdef NL_BIG_ENDIAN
00234                 uint32 val = NLMISC_BSWAP32(*(uint32*)buffer.buffer ());
00235 #else
00236                 uint32 val = *(uint32*)buffer.buffer ();
00237 #endif
00238 
00239 //              nldebug ("receive message number %u", val);
00240                 if (ReceiveNextValue != val)
00241                 {
00242                         nlstopex (("LNETL1: !!!LOST A MESSAGE!!! I received the message number %u but I'm waiting the message number %u (cnx %s), warn lecroart@nevrax.com with the log now please", val, ReceiveNextValue, id()->asString().c_str()));
00243                         // resync the message number
00244                         ReceiveNextValue = val;
00245                 }
00246                 ReceiveNextValue++;
00247 
00248 #ifdef USE_MESSAGE_RECORDER
00249                 if ( _MR_RecordingState == Record )
00250                 {
00251                         // Record received message
00252                         _MR_Recorder.recordNext( _MR_UpdateCounter, Receiving, *hostid, const_cast<CMessage&>(buffer) );
00253                 }
00254         }
00255         else
00256         {
00257                 // Retrieve received message loaded by dataAvailable()
00258                 buffer = _MR_Recorder.ReceivedMessages.front().Message;
00259                 _MR_Recorder.ReceivedMessages.pop();
00260         }
00261 #endif
00262 
00263         buffer.readType ();
00264 }
00265 
00266 /*
00267  *
00268  */
00269 TSockId CCallbackClient::getSockId (TSockId hostid)
00270 {
00271         nlassert (hostid == InvalidSockId);
00272         checkThreadId ();
00273 
00274         return id ();
00275 }
00276 
00277 
00278 /*
00279  * Connect to the specified host
00280  * Recorded : YES
00281  * Replayed : YES
00282  */
00283 void CCallbackClient::connect( const CInetAddress& addr )
00284 {
00285         checkThreadId ();
00286 
00287         SendNextValue = ReceiveNextValue = 0;
00288 
00289 #ifdef USE_MESSAGE_RECORDER
00290         if ( _MR_RecordingState != Replay )
00291         {
00292                 try
00293                 {
00294 #endif
00295 
00296                         // Connect
00297                         CBufClient::connect( addr );
00298 
00299 #ifdef USE_MESSAGE_RECORDER
00300                         if ( _MR_RecordingState == Record )
00301                         {
00302                                 // Record connection
00303                                 CMessage addrmsg;
00304                                 addrmsg.serial( const_cast<CInetAddress&>(addr) );
00305                                 _MR_Recorder.recordNext( _MR_UpdateCounter, Connecting, _BufSock, addrmsg );
00306                         }
00307                 }
00308                 catch ( ESocketConnectionFailed& )
00309                 {
00310                         if ( _MR_RecordingState == Record )
00311                         {
00312                                 // Record connection
00313                                 CMessage addrmsg;
00314                                 addrmsg.serial( const_cast<CInetAddress&>(addr) );
00315                                 _MR_Recorder.recordNext( _MR_UpdateCounter, ConnFailing, _BufSock, addrmsg );
00316                         }
00317                         throw;
00318                 }
00319         }
00320         else
00321         {
00322                 // Check the connection : failure or not
00323                 TNetworkEvent event = _MR_Recorder.replayConnectionAttempt( addr );
00324                 switch ( event )
00325                 {
00326                 case Connecting :
00327                         // Set the remote address
00328                         nlassert( ! _BufSock->Sock->connected() );
00329                         _BufSock->connect( addr, _NoDelay, true );
00330                         _PrevBytesDownloaded = 0;
00331                         _PrevBytesUploaded = 0;
00332                         /*_PrevBytesReceived = 0;
00333                         _PrevBytesSent = 0;*/
00334                         break;
00335                 case ConnFailing :
00336                         throw ESocketConnectionFailed( addr );
00337                         //break;
00338                 default :
00339                         nlwarning( "LNETL3C: No connection event in replay data, at update #%"NL_I64"u", _MR_UpdateCounter );
00340                 }
00341         }
00342 #endif
00343 }
00344 
00345 
00346 /*
00347  * Disconnect a connection
00348  * Recorded : YES
00349  * Replayed : YES
00350  */
00351 void CCallbackClient::disconnect( TSockId hostid )
00352 {
00353         nlassert (hostid == InvalidSockId);     // should always be InvalidSockId on client
00354         checkThreadId ();
00355 
00356         SendNextValue = ReceiveNextValue = 0;
00357 
00358         // Disconnect only if connected (same as physically connected for the client)
00359         if ( _BufSock->connectedState() )
00360         {
00361                 
00362 #ifdef USE_MESSAGE_RECORDER
00363                 if ( _MR_RecordingState != Replay )
00364                 {
00365 #endif
00366 
00367                         // Disconnect
00368                         CBufClient::disconnect ();
00369 
00370 #ifdef USE_MESSAGE_RECORDER
00371                 }
00372                 else
00373                 {
00374                         // Read (skip) disconnection in the file
00375                         if ( ! (_MR_Recorder.checkNextOne( _MR_UpdateCounter ) == Disconnecting) )
00376                         {
00377                                 nlwarning( "LNETL3C: No disconnection event in the replay data, at update #%"NL_I64"u", _MR_UpdateCounter );
00378                         }
00379                 }
00380                 // Record or replay disconnection (because disconnect() in the client does not push a disc. event)
00381                 noticeDisconnection( _BufSock );
00382 #endif
00383         }
00384 }
00385 
00386 
00387 #ifdef USE_MESSAGE_RECORDER
00388 
00389 
00390 /*
00391  * replay connection and disconnection callbacks, client version
00392  */
00393 bool CCallbackClient::replaySystemCallbacks()
00394 {
00395         do
00396         {
00397                 if ( _MR_Recorder.ReceivedMessages.empty() )
00398                 {
00399                         return false;
00400                 }
00401                 else
00402                 {
00403                         switch( _MR_Recorder.ReceivedMessages.front().Event )
00404                         {
00405                         case Receiving:
00406                                 return true;
00407 
00408                         case Disconnecting:
00409                                 nldebug( "Disconnection event" );
00410                                 _BufSock->setConnectedState( false );
00411         
00412                                 // Call callback if needed
00413                                 if ( disconnectionCallback() != NULL )
00414                                 {
00415                                         disconnectionCallback()( id(), argOfDisconnectionCallback() );
00416                                 }
00417                                 break;
00418 
00419                         default:
00420                                 nlerror( "LNETL1: Invalid system event type in client receive queue" );
00421                         }
00422                         // Extract system event
00423                         _MR_Recorder.ReceivedMessages.pop();
00424                 }
00425         }
00426         while ( true );
00427 }
00428 
00429 
00430 #endif // USE_MESSAGE_RECORDER
00431 
00432 
00433 } // NLNET