Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/lib/network/synchronizeable.cc @ 9598

Last change on this file since 9598 was 9598, checked in by patrick, 18 years ago

redirection seems to work good now

File size: 19.3 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11
12### File Specific:
13   main-programmer: Christoph Renner (rennerc@ee.ethz.ch)
14   co-programmer: Patrick Boenzli (patrick@orxonox.ethz.ch)
15*/
16
17#define DEBUG_MODULE_NETWORK
18
19#include "shared_network_data.h"
20#include "network_stream.h"
21#include "netdefs.h"
22#include "network_log.h"
23#include "network_game_manager.h"
24
25#include "state.h"
26
27#include <cassert>
28
29#include "synchronizeable.h"
30
31#include "converter.h"
32
33
34
35/**
36 *  default constructor
37 */
38Synchronizeable::Synchronizeable()
39{
40  this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
41  this->owner = 0;
42//   this->setIsServer(SharedNetworkData::getInstance()->getHostID() == 0);
43  this->uniqueID = NET_UID_UNASSIGNED;
44  this->networkStream = NULL;
45  this->bSynchronize = false;
46
47  if( State::isOnline())
48  {
49    NetworkStream* nd = SharedNetworkData::getInstance()->getDefaultSyncStream();
50    assert(nd != NULL);
51    nd->connectSynchronizeable(*this);
52    this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
53  }
54
55  /* make sure loadClassId is first synced var because this is read by networkStream */
56  assert( syncVarList.size() == 0 );
57  mLeafClassId = this->registerVarId( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
58
59  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
60  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
61}
62
63
64
65/**
66 *  default destructor deletes all unneded stuff
67 */
68Synchronizeable::~Synchronizeable()
69{
70  if ( this->networkStream )
71  {
72    this->networkStream->disconnectSynchronizeable(*this);
73
74    // remove the message manager only by the server
75    if ( (SharedNetworkData::getInstance()->isMasterServer() )
76           && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( CL_MESSAGE_MANAGER ) )
77      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
78  }
79
80  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
81  {
82    delete *it;
83  }
84  syncVarList.clear();
85
86  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
87  {
88    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
89    {
90      if ( (*it2)->data )
91      {
92        delete [] (*it2)->data;
93        (*it2)->data = NULL;
94      }
95      delete *it2;
96    }
97
98  }
99
100  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
101  {
102    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
103    {
104      if ( (*it2)->data )
105      {
106        delete [] (*it2)->data;
107        (*it2)->data = NULL;
108      }
109      delete *it2;
110    }
111  }
112}
113
114
115
116/**
117 * creates a diff image from two states
118 * @param userId: the userid of the user where the image will be sent to
119 * @param data: the binary data array to write to
120 * @param maxLength: maximal length of the data written (length of available space in the array)
121 * @param stateId: the state id that this diff will represent
122 * @param priorityTH: the priority threshold: all syncs below this threshold won't be synchronized
123 *
124 * @todo check for permissions
125 */
126int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
127{
128  //make sure this user has his history
129  if ( sentStates.size() <= userId )
130    sentStates.resize( userId+1 );
131
132  //calculate needed memory
133  int neededSize = 0;
134
135  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
136  {
137    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
138    neededSize += (*it)->getSize();
139  }
140
141  if ( !( neededSize <= maxLength ) )
142  {
143    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
144    assert(false);
145  }
146
147  //remove older states from history than fromStateId
148  StateHistory::iterator it = sentStates[userId].begin();
149
150  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
151    it++;
152
153  if ( it != sentStates[userId].begin() )
154  {
155    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
156    {
157      if ( (*it2)->data != NULL )
158      {
159        delete [] (*it2)->data;
160        (*it2)->data = NULL;
161      }
162
163      delete *it2;
164    }
165    sentStates[userId].erase( sentStates[userId].begin(), it );
166  }
167
168  //find state to create diff from
169  StateHistoryEntry * stateFrom = NULL;
170
171  it = sentStates[userId].begin();
172  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
173    it++;
174
175  if ( it == sentStates[userId].end() )
176  {
177    StateHistoryEntry * initialEntry = new StateHistoryEntry();
178
179    initialEntry->stateId = fromStateId;
180    initialEntry->dataLength = 0;
181    initialEntry->data = NULL;
182
183    stateFrom = initialEntry;
184
185    sentStates[userId].push_back( stateFrom );
186  }
187  else
188    stateFrom = (*it);
189
190  StateHistoryEntry * stateTo = new StateHistoryEntry;
191
192  sentStates[userId].push_back( stateTo );
193
194  stateTo->stateId = stateId;
195  stateTo->dataLength = neededSize;
196  stateTo->data = new byte[ neededSize ];
197
198  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
199
200  int i = 0;
201  int n;
202
203  bool hasPermission = false;
204  bool sizeChanged = false;
205
206  // now do the actual synchronization: kick all variables to write into a common buffer
207  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
208  {
209    // DATA PERMISSIONS
210    // check if this synchronizeable has the permissions to write the data
211
212    //  MASTER_SERVER |====> *
213    if( SharedNetworkData::getInstance()->isMasterServer() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
214      hasPermission = true;
215    else if( SharedNetworkData::getInstance()->isMasterServer() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
216      hasPermission = true;
217
218    // PROXY_SERVER  |====> *
219    else if( SharedNetworkData::getInstance()->isProxyServerActive() && (*it)->checkPermission( PERMISSION_PROXY_SERVER ))
220      hasPermission = true;
221    else if( SharedNetworkData::getInstance()->isProxyServerActive() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
222      hasPermission = true;
223    // PROXY_SERVER  |====> MASTER_SERVER
224    else if( SharedNetworkData::getInstance()->isProxyServerActive() && this->networkStream->isUserMasterServer(userId)
225             && this->networkStream->isUserLocal(userId) && (*it)->checkPermission( PERMISSION_MASTER_SERVER))
226      hasPermission = true;
227    // PROXY_SERVER  |====> CLIENT
228    else if( SharedNetworkData::getInstance()->isProxyServerActive() && this->networkStream->isUserClient(userId)
229             && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ) )
230      hasPermission = true;
231    else if( SharedNetworkData::getInstance()->isProxyServerActive() && this->networkStream->isUserClient(userId)
232             && (*it)->checkPermission( PERMISSION_MASTER_SERVER) )
233      hasPermission = true;
234
235    // OWNER         |====> *
236    else if( this->owner == SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
237      hasPermission = true;
238
239    // ALL           |====> *
240    else if( (*it)->checkPermission( PERMISSION_ALL ))
241      hasPermission = true;
242
243    else
244      hasPermission = false;
245
246
247    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
248      sizeChanged = true;
249
250    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
251    {
252      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
253      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
254      //PRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
255      stateTo->sizeList.push_back( n );
256      // this is only for very hardcore debug sessions
257      // (*it)->debug();
258      i += n;
259    }
260    else
261    {
262      for ( int j = 0; j<(*sizeIter); j++ )
263      {
264        assert( i < stateFrom->dataLength );
265        stateTo->data[i] = stateFrom->data[i];
266        i++;
267      }
268      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
269      stateTo->sizeList.push_back( (*sizeIter) );
270    }
271
272    if ( sizeIter != stateFrom->sizeList.end() )
273      sizeIter++;
274  }
275
276  if ( i != neededSize )
277  {
278    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
279    assert(false);
280  }
281
282  //write diff to data
283  for ( i = 0; i<neededSize; i++ )
284  {
285    if ( i < stateFrom->dataLength )
286      data[i] = stateTo->data[i] - stateFrom->data[i];
287    else
288      data[i] = stateTo->data[i];
289  }
290
291  return neededSize;
292}
293
294/**
295 * sets a new state out of a diff created on another host
296 * @param userId hostId of user who send me that diff
297 * @param data pointer to diff
298 * @param length length of diff
299 * @param stateId id of current state
300 * @param fromStateId id of the base state id
301 * @return number bytes read
302 *
303 * @todo check for permissions
304 */
305int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
306{
307  //make sure this user has his history
308  if ( recvStates.size() <= userId )
309    recvStates.resize( userId+1 );
310
311  //create new state
312  StateHistoryEntry * stateTo = new StateHistoryEntry();
313  stateTo->stateId = stateId;
314  stateTo->dataLength = length;
315  stateTo->data = new byte[ length ];
316
317
318  //find state to apply diff to
319  StateHistoryEntry * stateFrom = NULL;
320
321  // search the state from wich the diff is made of
322  StateHistory::iterator it = recvStates[userId].begin();
323  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
324    it++;
325
326  // if this is the first state to receive
327  if ( it == recvStates[userId].end() )
328  {
329    StateHistoryEntry * initialEntry = new StateHistoryEntry();
330
331    initialEntry->stateId = fromStateId;
332    initialEntry->dataLength = 0;
333    initialEntry->data = NULL;
334
335    stateFrom = initialEntry;
336
337    recvStates[userId].push_back( stateFrom );
338  }
339  else
340    stateFrom = (*it);
341
342
343  // apply diff
344  for ( int i = 0; i<length; i++ )
345  {
346    if ( i < stateFrom->dataLength )
347      stateTo->data[i] = stateFrom->data[i] + data[i];
348    else
349      stateTo->data[i] = data[i];
350  }
351
352  //add state to state history
353  recvStates[userId].push_back( stateTo );
354
355  int i = 0;
356  int n = 0;
357  std::list<int> changes;
358  bool hasPermission = false;
359
360  // extract the new state for every client
361  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
362  {
363    // DATA PERMISSIONS
364    // check if this synchronizeable has the permissions to write the data
365
366
367
368
369    //  *              <====|  MASTER_SERVER
370    if(  this->networkStream->isUserMasterServer( userId ) && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
371      hasPermission = true;
372    else if( this->networkStream->isUserMasterServer( userId ) && this->owner != SharedNetworkData::getInstance()->getHostID()
373             && (*it)->checkPermission( PERMISSION_OWNER ))
374      hasPermission = true;
375
376    //  *              <====|  PROXY_SERVER
377    else if( this->networkStream->isUserProxyServerActive( userId ) && this->owner != SharedNetworkData::getInstance()->getHostID()
378             && (*it)->checkPermission( PERMISSION_OWNER ))
379      hasPermission = true;
380    //  CLIENT         <====|  PROXY_SERVER
381    else if( this->networkStream->isUserProxyServerActive( userId ) && SharedNetworkData::getInstance()->isClient()
382             && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
383      hasPermission = true;
384    else if( this->networkStream->isUserProxyServerActive( userId ) && SharedNetworkData::getInstance()->isClient()
385             && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
386      hasPermission = true;
387    else if( this->networkStream->isUserProxyServerActive( userId )  && SharedNetworkData::getInstance()->isClient()
388             && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
389      hasPermission = true;
390    // MASTER_SERVER   <====|  PROXY_SERVER
391    else if( this->networkStream->isUserProxyServerActive( userId )  && SharedNetworkData::getInstance()->isMasterServer() &&
392             !this->networkStream->isUserLocal( userId ))
393      hasPermission = true;
394
395    //  *              <====|  OWNER
396    else if( this->owner == userId && (*it)->checkPermission( PERMISSION_OWNER ))
397      hasPermission = true;
398
399    //  *              <====|  ALL
400    else if( (*it)->checkPermission( PERMISSION_ALL ))
401      hasPermission = true;
402
403    else
404      hasPermission = false;
405
406
407
408    // if it has the permission to write do it
409    if( hasPermission)
410    {
411      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
412      i += n;
413      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
414      //PRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
415      //(*it)->debug();
416      if ( (*it)->getHasChanged() )
417      {
418        changes.push_back( (*it)->getVarId() );
419      }
420    }
421    else
422    {
423//       PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s perm: %d %d %d - %d %d %d\n", (*it)->getName().c_str(), (*it)->checkPermission( PERMISSION_MASTER_SERVER ), (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_ALL ), networkStream->isUserMasterServer( userId ), this->owner, userId );
424      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
425      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
426      //(*it)->debug();
427      i += n;
428    }
429  }
430
431  this->varChangeHandler( changes );
432
433  return i;
434}
435
436 /**
437 * override this function to be notified on change
438 * of your registred variables.
439 * @param id id's which have changed
440 */
441void Synchronizeable::varChangeHandler( std::list<int> & id )
442{
443}
444
445/**
446 * registers a varable to be synchronized over network
447 * @param var see src/lib/network/synchronizeable_var/ for available classes
448 */
449void Synchronizeable::registerVar( SynchronizeableVar * var )
450{
451  syncVarList.push_back( var );
452}
453
454/**
455 * registers a varable to be synchronized over network
456 * return value is passed to varChangeHandler on change
457 * @param var see src/lib/network/synchronizeable_var/ for available classes
458 * @return handle passed to varChangeHandler on changes
459 */
460int Synchronizeable::registerVarId( SynchronizeableVar * var )
461{
462  syncVarList.push_back( var );
463  var->setWatched( true );
464  var->setVarId( syncVarList.size()-1 );
465  return syncVarList.size()-1;
466}
467
468/**
469 * removed user's states from memory
470 * @param userId user to clean
471 */
472void Synchronizeable::cleanUpUser( int userId )
473{
474  if ( recvStates.size() > userId )
475  {
476    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
477    {
478      if ( (*it)->data )
479      {
480        delete [] (*it)->data;
481        (*it)->data = NULL;
482      }
483
484      delete *it;
485    }
486    recvStates[userId].clear();
487  }
488
489  if ( sentStates.size() > userId )
490  {
491
492    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
493    {
494      if ( (*it)->data )
495      {
496        delete [] (*it)->data;
497        (*it)->data = NULL;
498      }
499
500      delete *it;
501    }
502    sentStates[userId].clear();
503  }
504}
505
506/**
507 * this function is called after recieving a state.
508 * @param userId
509 * @param stateId
510 * @param fromStateId
511 */
512void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
513{
514   //make sure this user has his history
515  if ( recvStates.size() <= userId )
516    recvStates.resize( userId+1 );
517
518  //remove old states
519  StateHistory::iterator it = recvStates[userId].begin();
520
521#if 0
522  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
523    it++;
524
525  if ( it != recvStates[userId].begin() )
526  {
527    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
528    {
529      if ( (*it2)->data != NULL )
530      {
531        delete [] (*it2)->data;
532        (*it2)->data = NULL;
533      }
534    }
535    recvStates[userId].erase( recvStates[userId].begin(), it );
536  }
537#endif
538
539  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
540  {
541    if ( (*it)->stateId < fromStateId )
542    {
543      StateHistory::iterator delIt = it;
544      it ++;
545
546      if ( (*delIt)->data )
547      {
548        delete [] (*delIt)->data;
549        (*delIt)->data = NULL;
550      }
551      delete *delIt;
552      recvStates[userId].erase( delIt );
553
554      continue;
555    }
556    it++;
557  }
558
559  StateHistory::iterator fromState = recvStates[userId].end();
560  StateHistory::iterator toState = recvStates[userId].end();
561
562  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
563  {
564    if ( (*it)->stateId == stateId )
565      toState = it;
566    if ( (*it)->stateId == fromStateId )
567      fromState = it;
568
569    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
570      break;
571  }
572
573  // setStateDiff was not called and i know fromStateId
574  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
575  {
576    StateHistoryEntry * entry = new StateHistoryEntry;
577
578    entry->dataLength = (*fromState)->dataLength;
579    if ( entry->dataLength > 0 )
580    {
581      entry->data = new byte[entry->dataLength];
582
583      assert( (*fromState)->data );
584      memcpy( entry->data, (*fromState)->data, entry->dataLength );
585    }
586    else
587      entry->data = NULL;
588
589    entry->sizeList = (*fromState)->sizeList;
590    entry->stateId = stateId;
591
592    recvStates[userId].push_back(entry);
593  }
594}
595
596/**
597 * this function is called after sending a state
598 * @param userId
599 * @param stateId
600 * @param fromStateId
601 */
602void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
603{
604   //make sure this user has his history
605  if ( sentStates.size() <= userId )
606    sentStates.resize( userId+1 );
607
608   //remove old states
609  StateHistory::iterator it = sentStates[userId].begin();
610
611  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
612  {
613    if ( (*it)->stateId < fromStateId )
614    {
615      StateHistory::iterator delIt = it;
616      it ++;
617
618      if ( (*delIt)->data )
619      {
620        delete [] (*delIt)->data;
621        (*delIt)->data = NULL;
622      }
623      delete *delIt;
624      sentStates[userId].erase( delIt );
625
626      continue;
627    }
628    it++;
629  }
630
631
632  StateHistory::iterator fromState = sentStates[userId].end();
633  StateHistory::iterator toState = sentStates[userId].end();
634
635  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
636  {
637    if ( (*it)->stateId == stateId )
638      toState = it;
639    if ( (*it)->stateId == fromStateId )
640      fromState = it;
641
642    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
643      break;
644  }
645
646
647  // getStateDiff was not called and i know fromStateId
648  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
649  {
650    StateHistoryEntry * entry = new StateHistoryEntry;
651
652    entry->dataLength = (*fromState)->dataLength;
653    if ( entry->dataLength > 0 )
654    {
655      entry->data = new byte[entry->dataLength];
656
657      assert( (*fromState)->data );
658      memcpy( entry->data, (*fromState)->data, entry->dataLength );
659    }
660    else
661      entry->data = NULL;
662
663    entry->sizeList = (*fromState)->sizeList;
664    entry->stateId = stateId;
665
666    sentStates[userId].push_back(entry);
667  }
668
669}
670
671
672
Note: See TracBrowser for help on using the repository browser.