# 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_net_base.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/misc/string_id_array.h"
00029 #include "nel/misc/hierarchical_timer.h"
00030 
00031 #include "nel/net/buf_sock.h"
00032 #include "nel/net/callback_net_base.h"
00033 
00034 #ifdef USE_MESSAGE_RECORDER
00035 #ifdef NL_OS_WINDOWS
00036 #pragma message ( "NeL Net layer 3: message recorder enabled" )
00037 #endif // NL_OS_WINDOWS
00038 #include "nel/net/message_recorder.h"
00039 #else
00040 #ifdef NL_OS_WINDOWS
00041 #pragma message ( "NeL Net layer 3: message recorder disabled" )
00042 #endif // NL_OS_WINDOWS
00043 #endif
00044 
00045 
00046 using namespace std;
00047 using namespace NLMISC;
00048 
00049 namespace NLNET {
00050 
00051 
00052 /*
00053  *
00054  */
00055 void cbnbMessageRecvAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00056 {
00057         // receive a new message association
00058 
00059         CStringIdArray::TStringId size;
00060         msgin.serial (size);
00061 
00062         nldebug ("LNETL3NB_ASSOC: The other side gave me %d association strings", size);
00063 
00064         for (CStringIdArray::TStringId i = 0; i < size; i++)
00065         {
00066                 std::string name;
00067                 CStringIdArray::TStringId id;
00068 
00069                 msgin.serial (name);
00070                 msgin.serial (id);
00071 
00072                 // if id == -1, it means that there are no callback associated to this message
00073                 // it should not happen, it mean that one side send a message that the other side
00074                 // can't manage in his callbackarray.
00075                 // to resolve the problem, add the callback in the callbackarray in the other side
00076                 // and put NULL if you don't want to manage this message
00077                 nlassert (id != -1);
00078 
00079                 nldebug ("LNETL3NB_ASSOC:  association '%s' -> %d", name.c_str (), id);
00080                 netbase.getSIDA().addString (name, id);
00081         }
00082 }
00083 
00084 
00085 /*
00086  * the other side want to know some of my association, send them!
00087  */
00088 void cbnbMessageAskAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00089 {
00090         CMessage msgout (netbase.getSIDA(), "RA");
00091         CStringIdArray::TStringId size;
00092         msgin.serial (size);
00093 
00094         nldebug ("LNETL3NB_ASSOC: The other side want %d string associations", size);
00095 
00096         msgout.serial (size);
00097 
00098         for (sint i = 0; i < size; i++)
00099         {
00100                 string name;
00101                 msgin.serial (name);
00102                 nldebug ("LNETL3NB_ASSOC:  sending association '%s' -> %d", name.c_str (), netbase._OutputSIDA.getId(name));
00103 
00104                 // if this assert occurs, it means that the other side ask an unknown message
00105                 // or that there are different types of client (with differents callbackarray) and one of the client doesn't have this callback
00106                 nlassert(netbase._OutputSIDA.getId(name) != -1);
00107 
00108                 msgout.serial (name);
00109 
00110                 CStringIdArray::TStringId id = netbase._OutputSIDA.getId (name);
00111                 msgout.serial (id);
00112         }
00113         // send the message to the other side
00114         netbase.send (msgout, from);
00115 }
00116 
00117 static TCallbackItem cbnbMessageAssociationArray[] =
00118 {
00119         { "AA", cbnbMessageAskAssociations },
00120         { "RA", cbnbMessageRecvAssociations },
00121 };
00122 
00123 
00124 /*
00125  * Disconnection callback
00126  */
00127 void cbnbNewDisconnection (TSockId from, void *data)
00128 {
00129         nlassert (data != NULL);
00130         CCallbackNetBase *base = (CCallbackNetBase *)data;
00131 
00132         nldebug("LNETL3NB: cbnbNewDisconnection()");
00133 
00134 #ifdef USE_MESSAGE_RECORDER
00135         // Record or replay disconnection
00136         base->noticeDisconnection( from );
00137 #endif
00138         
00139         // Call the client callback if necessary
00140         if (base->_DisconnectionCallback != NULL)
00141                 base->_DisconnectionCallback (from, base->_DisconnectionCbArg);
00142 }
00143 
00144 
00145 /*
00146  * Constructor
00147  */
00148 CCallbackNetBase::CCallbackNetBase(  TRecordingState rec, const string& recfilename, bool recordall ) :
00149         _FirstUpdate (true), _DisconnectionCallback(NULL), _DisconnectionCbArg(NULL)
00150 #ifdef USE_MESSAGE_RECORDER
00151         , _MR_RecordingState(rec), _MR_UpdateCounter(0)
00152 #endif
00153 {
00154         _ThreadId = getThreadId ();
00155         _NewDisconnectionCallback = cbnbNewDisconnection;
00156 
00157         _BytesSent = 0;
00158         _BytesReceived = 0;
00159 
00160         createDebug(); // for addNegativeFilter to work even in release and releasedebug modes
00161 
00162         // add the callback needed to associate messages with id
00163         addCallbackArray (cbnbMessageAssociationArray, sizeof (cbnbMessageAssociationArray) / sizeof (cbnbMessageAssociationArray[0]));
00164 
00165 #ifdef USE_MESSAGE_RECORDER
00166         switch ( _MR_RecordingState )
00167         {
00168         case Record :
00169                 _MR_Recorder.startRecord( recfilename, recordall );
00170                 break;
00171         case Replay :
00172                 _MR_Recorder.startReplay( recfilename );
00173                 break;
00174         default:;
00175                 // No recording
00176         }
00177 #endif
00178 }
00179 
00180 
00181 /*
00182  *      Append callback array with the specified array
00183  */
00184 void CCallbackNetBase::addCallbackArray (const TCallbackItem *callbackarray, CStringIdArray::TStringId arraysize)
00185 {
00186         checkThreadId ();
00187 
00188         // be sure that the 2 array have the same size
00189         nlassert (_CallbackArray.size () == (uint)_OutputSIDA.size ());
00190 
00191         if (arraysize == 1 && callbackarray[0].Callback == NULL && string("") == callbackarray[0].Key)
00192         {
00193                 // it's an empty array, ignore it
00194                 return;
00195         }
00196 
00197         // resize the array
00198         sint oldsize = _CallbackArray.size();
00199 
00200         _CallbackArray.resize (oldsize + arraysize);
00201         _OutputSIDA.resize (oldsize + arraysize);
00202 
00203 //TOO MUCH MESSAGE      nldebug ("L3NB_CB: Adding %d callback to the array", arraysize);
00204 
00205         for (sint i = 0; i < arraysize; i++)
00206         {
00207                 CStringIdArray::TStringId ni = oldsize + i;
00208 //TOO MUCH MESSAGE              nldebug ("L3NB_CB: Adding callback to message '%s', id '%d'", callbackarray[i].Key, ni);
00209                 // copy callback value
00210                 
00211                 _CallbackArray[ni] = callbackarray[i];
00212                 // add the string to the string id array
00213                 _OutputSIDA.addString (callbackarray[i].Key, ni);
00214 
00215         }
00216 //      nldebug ("LNETL3NB_CB: Added %d callback Now, there's %d callback associated with message type", arraysize, _CallbackArray.size ());
00217 }
00218 
00219 
00220 /*
00221  * processOneMessage()
00222  */
00223 void CCallbackNetBase::processOneMessage ()
00224 {
00225         checkThreadId ();
00226 
00227         // slow down the layer H_AUTO (CCallbackNetBase_processOneMessage);
00228 
00229         CMessage msgin (_OutputSIDA, "", true);
00230         TSockId tsid;
00231         receive (msgin, &tsid);
00232 
00233         _BytesReceived += msgin.length ();
00234         
00235         // now, we have to call the good callback
00236         NLMISC::CStringIdArray::TStringId pos = -1;
00237         if (msgin.TypeHasAnId)
00238         {
00239                 pos = msgin.getId ();
00240         }
00241         else
00242         {
00243                 std::string name = msgin.getName ();
00244                 sint16 i;
00245                 for (i = 0; i < (sint16) _CallbackArray.size (); i++)
00246                 {
00247                         if (name == _CallbackArray[i].Key)
00248                         {
00249                                 pos = i;
00250                                 break;
00251                         }
00252                 }
00253         }
00254 
00255         TMsgCallback    cb = NULL;
00256         if (pos < 0 || pos >= (sint16) _CallbackArray.size ())
00257         {
00258                 if (_DefaultCallback == NULL)
00259                 {
00260                         nlwarning ("LNETL3NB_CB: Callback %s not found in _CallbackArray", msgin.toString().c_str());
00261                 }
00262                 else
00263                 {
00264                         cb = _DefaultCallback;
00265                 }
00266         }
00267         else
00268         {
00269                 cb = _CallbackArray[pos].Callback;
00270         }
00271 
00272         TSockId realid = getSockId (tsid);
00273 
00274         if (!realid->AuthorizedCallback.empty() && msgin.getName() != realid->AuthorizedCallback)
00275         {
00276                 nlwarning ("LNETL3NB_CB: %s try to call the callback %s but only %s is authorized. Disconnect him!", tsid->asString().c_str(), msgin.toString().c_str(), tsid->AuthorizedCallback.c_str());
00277                 disconnect (tsid);
00278         }
00279         else if (cb == NULL)
00280         {
00281                 nlwarning ("LNETL3NB_CB: Callback %s is NULL, can't call it", msgin.toString().c_str());
00282         }
00283         else
00284         {
00285                 nldebug ("LNETL3NB_CB: Calling callback (%s)%s", msgin.getName().c_str(), (cb==_DefaultCallback)?" DEFAULT_CB":"");
00286                 cb(msgin, realid, *this);
00287         }
00288         
00289 /*
00290         if (pos < 0 || pos >= (sint16) _CallbackArray.size ())
00291         {
00292                 if (_DefaultCallback == NULL)
00293                         nlwarning ("LNETL3NB_CB: Callback %s not found in _CallbackArray", msgin.toString().c_str());
00294                 else
00295                 {
00296                         // ...
00297                 }
00298         }
00299         else
00300         {
00301                 TSockId realid = getSockId (tsid);
00302 
00303                 if (!realid->AuthorizedCallback.empty() && msgin.getName() != realid->AuthorizedCallback)
00304                 {
00305                         nlwarning ("LNETL3NB_CB: %s try to call the callback %s but only %s is authorized. Disconnect him!", tsid->asString().c_str(), msgin.toString().c_str(), tsid->AuthorizedCallback.c_str());
00306                         disconnect (tsid);
00307                 }
00308                 else if (_CallbackArray[pos].Callback == NULL)
00309                 {
00310                         nlwarning ("LNETL3NB_CB: Callback %s is NULL, can't call it", msgin.toString().c_str());
00311                 }
00312                 else
00313                 {
00314                         nldebug ("LNETL3NB_CB: Calling callback (%s)", _CallbackArray[pos].Key);
00315                         _CallbackArray[pos].Callback (msgin, realid, *this);
00316                 }
00317         }
00318 */
00319 }
00320 
00321 
00322 
00323 /*
00324  * baseUpdate
00325  * Recorded : YES
00326  * Replayed : YES
00327  */
00328 void CCallbackNetBase::baseUpdate (sint32 timeout)
00329 {
00330         checkThreadId ();
00331 
00332         // slow down the layer H_AUTO (CCallbackNetBase_baseUpdate);
00333 
00334         nlassert( timeout >= -1 );
00335         TTime t0 = CTime::getLocalTime();
00336 
00337         //
00338         // The first time, we init time counters
00339         //
00340         if (_FirstUpdate)
00341         {
00342 //              nldebug("LNETL3NB: First update()");
00343                 _FirstUpdate = false;
00344                 _LastUpdateTime = t0;
00345                 _LastMovedStringArray = t0;
00346         }
00347 
00348         //
00349         // Every 1 seconds if we have new unknown association, we ask them to the other side
00350         //
00351         if (t0 - _LastUpdateTime >  1000)
00352         {
00353 //              nldebug("LNETL3NB: baseUpdate()");
00354                 _LastUpdateTime = t0;
00355 
00356                 const set<string> &sa = _InputSIDA.getNeedToAskedStringArray ();
00357                 if (!sa.empty ())
00358                 {
00359                         CMessage msgout (_InputSIDA, "AA");
00360                         //nlassert (sa.size () < 65536); // no size limit anymore
00361                         CStringIdArray::TStringId size = sa.size ();
00362                         nldebug ("LNETL3NB_ASSOC: I need %d string association, ask them to the other side", size);
00363                         msgout.serial (size);
00364                         for (set<string>::iterator it = sa.begin(); it != sa.end(); it++)
00365                         {
00366                                 nldebug ("LNETL3NB_ASSOC:  what is the id of '%s'?", (*it).c_str ());
00367                                 string str(*it);
00368                                 msgout.serial (str);
00369                         }
00370                         // send the message to the other side
00371                         send (msgout, 0);
00372                         _InputSIDA.moveNeedToAskToAskedStringArray();
00373                         _LastMovedStringArray = t0;
00374                 }
00375         }
00376 
00377         //
00378         // Every 60 seconds if we have not answered association, we ask again to get them!
00379         //
00380         if (!_InputSIDA.getAskedStringArray().empty() && t0 - _LastMovedStringArray > 60000)
00381         {
00382                 // we didn't have an answer for the association, resend them
00383                 const set<string> sa = _InputSIDA.getAskedStringArray ();
00384                 CMessage msgout (_InputSIDA, "AA");
00385                 //nlassert (sa.size () < 65536); // no size limit anymore
00386                 CStringIdArray::TStringId size = sa.size ();
00387                 nldebug ("LNETL3NB_ASSOC: client didn't answer my asked association, retry! I need %d string association, ask them to the other side", size);
00388                 msgout.serial (size);
00389                 for (set<string>::iterator it = sa.begin(); it != sa.end(); it++)
00390                 {
00391                         nldebug ("LNETL3NB_ASSOC:  what is the id of '%s'?", (*it).c_str ());
00392                         string str(*it);
00393                         msgout.serial (str);
00394                 }
00395                 // sends the message to the other side
00396                 send (msgout, 0);
00397                 _LastMovedStringArray = t0;
00398         }
00399 
00400         /*
00401          * timeout -1    =>  read one message in the queue or nothing if no message in queue
00402          * timeout 0     =>  read all messages in the queue
00403          * timeout other =>  read all messages in the queue until timeout expired (at least all one time)
00404          */
00405 
00406         bool exit = false;
00407 
00408         while (!exit)
00409         {
00410                 // process all messages in the queue
00411                 while (dataAvailable ())
00412                 {
00413                         processOneMessage ();
00414                         if (timeout == -1)
00415                         {
00416                                 exit = true;
00417                                 break;
00418                         }
00419                 }
00420 
00421                 // need to exit?
00422                 if (timeout == 0 || (sint32)(CTime::getLocalTime() - t0) > timeout)
00423                 {
00424                         exit = true;
00425                 }
00426                 else
00427                 {
00428                         // enable multithreading on windows :-/
00429                         // slow down the layer H_AUTO (CCallbackNetBase_baseUpdate_nlSleep);
00430                         nlSleep (10);
00431                 }
00432         }
00433 
00434 #ifdef USE_MESSAGE_RECORDER
00435         _MR_UpdateCounter++;
00436 #endif
00437 
00438 }
00439 
00440 
00441 const   CInetAddress& CCallbackNetBase::hostAddress (TSockId hostid)
00442 {
00443         // should never be called
00444         nlstop;
00445         static CInetAddress tmp;
00446         return tmp;
00447 }
00448 
00449 void    CCallbackNetBase::setOtherSideAssociations (const char **associationarray, NLMISC::CStringIdArray::TStringId arraysize)
00450 {
00451         checkThreadId ();
00452 
00453         nldebug ("LNETL3NB_ASSOC: setOtherSideAssociations() sets %d association strings", arraysize);
00454 
00455         for (sint i = 0; i < arraysize; i++)
00456         {
00457                 nldebug ("LNETL3NB_ASSOC:  association '%s' -> %d", associationarray[i], i);
00458                 getSIDA().addString (associationarray[i], i);
00459         }
00460 }
00461 
00462 void    CCallbackNetBase::displayAllMyAssociations ()
00463 {
00464         checkThreadId ();
00465 
00466         _OutputSIDA.display ();
00467 }
00468 
00469 void    CCallbackNetBase::authorizeOnly (const char *callbackName, TSockId hostid)
00470 {
00471         checkThreadId ();
00472 
00473         nldebug ("LNETL3NB: authorizeOnly (%s, %s)", callbackName, hostid->asString().c_str());
00474 
00475         hostid = getSockId (hostid);
00476         
00477         nlassert (hostid != InvalidSockId);
00478 
00479         hostid->AuthorizedCallback = (callbackName == NULL)?"":callbackName;
00480 }
00481 
00482 
00483 #ifdef USE_MESSAGE_RECORDER
00484 
00485 /*
00486  * Replay dataAvailable() in replay mode
00487  */
00488 bool CCallbackNetBase::replayDataAvailable()
00489 {
00490         nlassert( _MR_RecordingState == Replay );
00491 
00492         if ( _MR_Recorder.ReceivedMessages.empty() )
00493         {
00494                 // Fill the queue of received messages related to the present update
00495                 _MR_Recorder.replayNextDataAvailable( _MR_UpdateCounter );
00496         }
00497 
00498         return replaySystemCallbacks();
00499 }
00500 
00501 
00502 /*
00503  * Record or replay disconnection
00504  */
00505 void CCallbackNetBase::noticeDisconnection( TSockId hostid )
00506 {
00507         nlassert (hostid != InvalidSockId);     // invalid hostid
00508         if ( _MR_RecordingState != Replay )
00509         {
00510                 if ( _MR_RecordingState == Record )
00511                 {
00512                         // Record disconnection
00513                         CMessage emptymsg;
00514                         _MR_Recorder.recordNext( _MR_UpdateCounter, Disconnecting, hostid, emptymsg );
00515                 }
00516         }
00517         else
00518         {
00519                 // Replay disconnection
00520                 hostid->disconnect( false );
00521         }
00522 }
00523 
00524 #endif // USE_MESSAGE_RECORDER
00525 
00526 
00527 
00528 /*
00529  * checkThreadId
00530  */
00531 void CCallbackNetBase::checkThreadId () const
00532 {
00533 /*      some people use this class in different thread but with a mutex to be sure to have
00534         no concurent access
00535         if (getThreadId () != _ThreadId)
00536         {
00537                 nlerror ("You try to access to the same CCallbackClient or CCallbackServer with 2 differents thread (%d and %d)", _ThreadId, getThreadId());
00538         }
00539 */
00540 }
00541 
00542 
00543 } // NLNET
00544