Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9483 was 9483, checked in by patrick, 19 years ago

giving the proxy server more rights to write the clients

File size: 18.3 KB
RevLine 
[5523]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
[5547]11
[5523]12### File Specific:
[9406]13   main-programmer: Christoph Renner (rennerc@ee.ethz.ch)
14   co-programmer: Patrick Boenzli (patrick@orxonox.ethz.ch)
[5547]15*/
[5523]16
[6139]17#define DEBUG_MODULE_NETWORK
18
[6695]19#include "shared_network_data.h"
20#include "network_stream.h"
[5547]21#include "netdefs.h"
[7954]22#include "network_log.h"
[8068]23#include "network_game_manager.h"
[5529]24
[6695]25#include "state.h"
[5996]26
[6753]27#include <cassert>
[6695]28
29#include "synchronizeable.h"
30
[9406]31#include "converter.h"
[6695]32
33
[9406]34
[5547]35/**
[5807]36 *  default constructor
[5547]37 */
[5996]38Synchronizeable::Synchronizeable()
[5997]39{
[6341]40  this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
[8068]41  this->owner = 0;
[9406]42//   this->setIsServer(SharedNetworkData::getInstance()->getHostID() == 0);
[6695]43  this->uniqueID = NET_UID_UNASSIGNED;
[6145]44  this->networkStream = NULL;
[6695]45  this->bSynchronize = false;
[9406]46
[6695]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  }
[7954]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" ) );
[9406]58
[7954]59  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
60  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
[5997]61}
62
[5523]63
[5996]64
[5547]65/**
[5807]66 *  default destructor deletes all unneded stuff
[5547]67 */
68Synchronizeable::~Synchronizeable()
[6139]69{
70  if ( this->networkStream )
[9110]71  {
[6139]72    this->networkStream->disconnectSynchronizeable(*this);
[9406]73
[9474]74    // remove the message manager only by the server
75    if ( (SharedNetworkData::getInstance()->isMasterServer() )
[9406]76           && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( CL_MESSAGE_MANAGER ) )
[9110]77      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
78  }
[9406]79
[8623]80  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
81  {
82    delete *it;
83  }
84  syncVarList.clear();
[9406]85
[8623]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  }
[9406]99
[8623]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  }
[6139]112}
[5523]113
114
[6695]115
[5547]116/**
[9406]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
[5547]125 */
[7954]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 );
[5547]131
[7954]132  //calculate needed memory
133  int neededSize = 0;
[5997]134
[7954]135  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
[8147]136  {
137    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
[7954]138    neededSize += (*it)->getSize();
[8147]139  }
[5997]140
[7954]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      }
[9406]162
[8623]163      delete *it2;
[7954]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;
[9406]184
[8623]185    sentStates[userId].push_back( stateFrom );
[7954]186  }
187  else
188    stateFrom = (*it);
189
[8623]190  StateHistoryEntry * stateTo = new StateHistoryEntry;
[7954]191
[8623]192  sentStates[userId].push_back( stateTo );
[9406]193
[7954]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;
[9406]202
203  bool hasPermission = false;
[8623]204  bool sizeChanged = false;
[7954]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  {
[9406]209    // DATA PERMISSIONS
210    // check if this synchronizeable has the permissions to write the data
211
212    // first check MASTER_SERVER permissions
213    if( SharedNetworkData::getInstance()->isMasterServer() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
214      hasPermission = true;
215    // now check PROXY_SERVER permissions
[9458]216    else if( SharedNetworkData::getInstance()->isProxyServerActive() && (*it)->checkPermission( PERMISSION_PROXY_SERVER ))
[9406]217      hasPermission = true;
218    // now check OWNER permissions
219    else if( this->owner == SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
220      hasPermission = true;
221    // now check ALL permissions
222    else if( (*it)->checkPermission( PERMISSION_ALL ))
223      hasPermission = true;
224    // SPECIAL: get write permissions if i am master server and i am able to overwrite the client stuff
[9483]225#warning this could probably override also clients that are connected to another proxy: the master server overwrites it
[9406]226    else if( SharedNetworkData::getInstance()->isMasterServer() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
227      hasPermission = true;
228    // SPECIAL: get write permissions if i am proxy server and i am able to overwrite the client stuff
[9483]229    else if( SharedNetworkData::getInstance()->isProxyServerActive()  && this->owner != userId &&
230             (*it)->checkPermission( PERMISSION_OWNER ) && this->networkStream->isUserClient(userId))
231      hasPermission = true;
[9406]232    else
233      hasPermission = false;
234
235
236    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
[8623]237      sizeChanged = true;
[9406]238
[8623]239    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
[7954]240    {
241      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
242      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
[9406]243      //PRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
[7954]244      stateTo->sizeList.push_back( n );
[9406]245      // this is only for very hardcore debug sessions
246      // (*it)->debug();
[7954]247      i += n;
248    }
249    else
250    {
251      for ( int j = 0; j<(*sizeIter); j++ )
252      {
253        assert( i < stateFrom->dataLength );
254        stateTo->data[i] = stateFrom->data[i];
255        i++;
256      }
257      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
258      stateTo->sizeList.push_back( (*sizeIter) );
259    }
260
261    if ( sizeIter != stateFrom->sizeList.end() )
262      sizeIter++;
263  }
264
[8147]265  if ( i != neededSize )
266  {
[9406]267    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
[8147]268    assert(false);
269  }
[7954]270
271  //write diff to data
272  for ( i = 0; i<neededSize; i++ )
273  {
274    if ( i < stateFrom->dataLength )
275      data[i] = stateTo->data[i] - stateFrom->data[i];
276    else
277      data[i] = stateTo->data[i];
278  }
279
280  return neededSize;
281}
282
[5997]283/**
[7954]284 * sets a new state out of a diff created on another host
285 * @param userId hostId of user who send me that diff
286 * @param data pointer to diff
287 * @param length length of diff
288 * @param stateId id of current state
289 * @param fromStateId id of the base state id
290 * @return number bytes read
[9406]291 *
[7954]292 * @todo check for permissions
[5997]293 */
[7954]294int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]295{
[7954]296  //make sure this user has his history
297  if ( recvStates.size() <= userId )
298    recvStates.resize( userId+1 );
299
300  //create new state
301  StateHistoryEntry * stateTo = new StateHistoryEntry();
302  stateTo->stateId = stateId;
303  stateTo->dataLength = length;
304  stateTo->data = new byte[ length ];
305
306
307  //find state to apply diff to
308  StateHistoryEntry * stateFrom = NULL;
309
[9406]310  // search the state from wich the diff is made of
[7954]311  StateHistory::iterator it = recvStates[userId].begin();
312  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
313    it++;
314
[9406]315  // if this is the first state to receive
[7954]316  if ( it == recvStates[userId].end() )
317  {
318    StateHistoryEntry * initialEntry = new StateHistoryEntry();
319
320    initialEntry->stateId = fromStateId;
321    initialEntry->dataLength = 0;
322    initialEntry->data = NULL;
323
324    stateFrom = initialEntry;
[9406]325
[8623]326    recvStates[userId].push_back( stateFrom );
[7954]327  }
[5997]328  else
[7954]329    stateFrom = (*it);
[9406]330
331
332  // apply diff
[7954]333  for ( int i = 0; i<length; i++ )
334  {
335    if ( i < stateFrom->dataLength )
336      stateTo->data[i] = stateFrom->data[i] + data[i];
337    else
338      stateTo->data[i] = data[i];
339  }
[9406]340
[7954]341  //add state to state history
342  recvStates[userId].push_back( stateTo );
[9406]343
[7954]344  int i = 0;
345  int n = 0;
346  std::list<int> changes;
[9406]347  bool hasPermission = false;
348
349  // extract the new state for every client
[7954]350  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
351  {
[9406]352    // DATA PERMISSIONS
353    // check if this synchronizeable has the permissions to write the data
354
355    // first check MASTER_SERVER permissions
356    if(  this->networkStream->isUserMasterServer( userId ) && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
357      hasPermission = true;
358    // now check PROXY_SERVER permissions
[9458]359    else if( this->networkStream->isUserProxyServerActive( userId )  && (*it)->checkPermission( PERMISSION_PROXY_SERVER ))
[9406]360      hasPermission = true;
361    // now check OWNER permissions
362    else if( this->owner == userId && (*it)->checkPermission( PERMISSION_OWNER ))
363      hasPermission = true;
364    // now check ALL permissions
365    else if( (*it)->checkPermission( PERMISSION_ALL ))
366      hasPermission = true;
367    // SPECIAL: get write permissions if im sending to a master server that does not own this sync
368    else if( this->networkStream->isUserMasterServer( userId ) && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
369      hasPermission = true;
370    // SPECIAL: get write permissions if im sending to a proxy server that does not own this sync
[9483]371    else if( this->networkStream->isUserProxyServerActive( userId )  && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ) && SharedNetworkData::getInstance()->isClient())
372      hasPermission = true;
[9406]373    else
374      hasPermission = false;
375
376
377
378    // if it has the permission to write do it
379    if( hasPermission)
[7954]380    {
381      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
382      i += n;
[9406]383      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
384      //PRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[7954]385      //(*it)->debug();
386      if ( (*it)->getHasChanged() )
387      {
388        changes.push_back( (*it)->getVarId() );
389      }
390    }
391    else
392    {
[9406]393//      PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s %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->isUserServer( userId ), this->owner, userId );
[7954]394      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
[9406]395      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[7954]396      //(*it)->debug();
397      i += n;
398    }
399  }
400
401  this->varChangeHandler( changes );
[9406]402
[7954]403  return i;
[5997]404}
405
[7954]406 /**
407 * override this function to be notified on change
408 * of your registred variables.
409 * @param id id's which have changed
410 */
411void Synchronizeable::varChangeHandler( std::list<int> & id )
412{
413}
[6695]414
[5997]415/**
[7954]416 * registers a varable to be synchronized over network
417 * @param var see src/lib/network/synchronizeable_var/ for available classes
[5997]418 */
[7954]419void Synchronizeable::registerVar( SynchronizeableVar * var )
[5997]420{
[7954]421  syncVarList.push_back( var );
[5997]422}
423
424/**
[7954]425 * registers a varable to be synchronized over network
426 * return value is passed to varChangeHandler on change
427 * @param var see src/lib/network/synchronizeable_var/ for available classes
428 * @return handle passed to varChangeHandler on changes
[5997]429 */
[7954]430int Synchronizeable::registerVarId( SynchronizeableVar * var )
[5997]431{
[7954]432  syncVarList.push_back( var );
433  var->setWatched( true );
434  var->setVarId( syncVarList.size()-1 );
435  return syncVarList.size()-1;
[5997]436}
437
438/**
[7954]439 * removed user's states from memory
440 * @param userId user to clean
[5997]441 */
[7954]442void Synchronizeable::cleanUpUser( int userId )
[5997]443{
[8228]444  if ( recvStates.size() > userId )
[7954]445  {
[8228]446    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
[7954]447    {
[8228]448      if ( (*it)->data )
[8623]449      {
[8228]450        delete [] (*it)->data;
[8623]451        (*it)->data = NULL;
452      }
[9406]453
[8228]454      delete *it;
[7954]455    }
[8228]456    recvStates[userId].clear();
[7954]457  }
[9406]458
[8228]459  if ( sentStates.size() > userId )
[7954]460  {
[9406]461
[8228]462    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
[7954]463    {
[8228]464      if ( (*it)->data )
[8623]465      {
[8228]466        delete [] (*it)->data;
[8623]467        (*it)->data = NULL;
468      }
[9406]469
[8228]470      delete *it;
[7954]471    }
[8228]472    sentStates[userId].clear();
[7954]473  }
[5997]474}
[6139]475
[6341]476/**
[7954]477 * this function is called after recieving a state.
[9406]478 * @param userId
479 * @param stateId
480 * @param fromStateId
[6341]481 */
[7954]482void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
[6341]483{
[7954]484   //make sure this user has his history
485  if ( recvStates.size() <= userId )
486    recvStates.resize( userId+1 );
[9406]487
[7954]488  //remove old states
489  StateHistory::iterator it = recvStates[userId].begin();
490
491#if 0
492  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
493    it++;
494
495  if ( it != recvStates[userId].begin() )
496  {
497    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
498    {
499      if ( (*it2)->data != NULL )
500      {
501        delete [] (*it2)->data;
502        (*it2)->data = NULL;
503      }
504    }
505    recvStates[userId].erase( recvStates[userId].begin(), it );
506  }
507#endif
508
509  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
510  {
511    if ( (*it)->stateId < fromStateId )
512    {
513      StateHistory::iterator delIt = it;
514      it ++;
[9406]515
[7954]516      if ( (*delIt)->data )
[8623]517      {
[7954]518        delete [] (*delIt)->data;
[8623]519        (*delIt)->data = NULL;
520      }
521      delete *delIt;
[7954]522      recvStates[userId].erase( delIt );
[9406]523
[7954]524      continue;
525    }
526    it++;
527  }
[9406]528
[7954]529  StateHistory::iterator fromState = recvStates[userId].end();
530  StateHistory::iterator toState = recvStates[userId].end();
[9406]531
[7954]532  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
533  {
534    if ( (*it)->stateId == stateId )
535      toState = it;
536    if ( (*it)->stateId == fromStateId )
537      fromState = it;
[9406]538
[7954]539    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
540      break;
541  }
[9406]542
[7954]543  // setStateDiff was not called and i know fromStateId
544  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
545  {
546    StateHistoryEntry * entry = new StateHistoryEntry;
[9406]547
[7954]548    entry->dataLength = (*fromState)->dataLength;
549    if ( entry->dataLength > 0 )
550    {
551      entry->data = new byte[entry->dataLength];
[9406]552
[7954]553      assert( (*fromState)->data );
554      memcpy( entry->data, (*fromState)->data, entry->dataLength );
555    }
556    else
557      entry->data = NULL;
[9406]558
[7954]559    entry->sizeList = (*fromState)->sizeList;
560    entry->stateId = stateId;
[9406]561
[7954]562    recvStates[userId].push_back(entry);
563  }
[6341]564}
[6139]565
[6341]566/**
[7954]567 * this function is called after sending a state
[9406]568 * @param userId
569 * @param stateId
570 * @param fromStateId
[6341]571 */
[7954]572void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
[6341]573{
[7954]574   //make sure this user has his history
575  if ( sentStates.size() <= userId )
576    sentStates.resize( userId+1 );
577
578   //remove old states
579  StateHistory::iterator it = sentStates[userId].begin();
580
581  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
582  {
583    if ( (*it)->stateId < fromStateId )
584    {
585      StateHistory::iterator delIt = it;
586      it ++;
[9406]587
[7954]588      if ( (*delIt)->data )
[8623]589      {
[7954]590        delete [] (*delIt)->data;
[8623]591        (*delIt)->data = NULL;
592      }
593      delete *delIt;
[7954]594      sentStates[userId].erase( delIt );
[9406]595
[7954]596      continue;
597    }
598    it++;
599  }
600
[9406]601
[7954]602  StateHistory::iterator fromState = sentStates[userId].end();
603  StateHistory::iterator toState = sentStates[userId].end();
[9406]604
[7954]605  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
606  {
607    if ( (*it)->stateId == stateId )
608      toState = it;
609    if ( (*it)->stateId == fromStateId )
610      fromState = it;
[9406]611
[7954]612    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
613      break;
614  }
615
[9406]616
[7954]617  // getStateDiff was not called and i know fromStateId
618  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
619  {
620    StateHistoryEntry * entry = new StateHistoryEntry;
[9406]621
[7954]622    entry->dataLength = (*fromState)->dataLength;
623    if ( entry->dataLength > 0 )
624    {
625      entry->data = new byte[entry->dataLength];
[9406]626
[7954]627      assert( (*fromState)->data );
628      memcpy( entry->data, (*fromState)->data, entry->dataLength );
629    }
630    else
631      entry->data = NULL;
[9406]632
[7954]633    entry->sizeList = (*fromState)->sizeList;
634    entry->stateId = stateId;
[9406]635
[7954]636    sentStates[userId].push_back(entry);
637  }
[9406]638
[6341]639}
[6139]640
[6341]641
642
Note: See TracBrowser for help on using the repository browser.