Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

committing my weekends work: 2100 lines :D

  • proxy server now accepts and synchronizes clients like a master server
  • network manager got different network setup interface
  • network stream got different constructure scheme
  • permissions checking and algorithm extended and changed
  • starting ability to connect to multiple network nodes at the same time
  • some very much smaller changes here and there
File size: 18.1 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:
[9396]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
[9386]31#include "converter.h"
[6695]32
33
[9386]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;
[9347]42//   this->setIsServer(SharedNetworkData::getInstance()->getHostID() == 0);
[6695]43  this->uniqueID = NET_UID_UNASSIGNED;
[6145]44  this->networkStream = NULL;
[6695]45  this->bSynchronize = false;
[9347]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" ) );
[9347]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);
[9347]73
[9396]74    if ( (SharedNetworkData::getInstance()->isMasterServer() || SharedNetworkData::getInstance()->isProxyServer() )
75           && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( CL_MESSAGE_MANAGER ) )
[9110]76      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
77  }
[9347]78
[8623]79  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
80  {
81    delete *it;
82  }
83  syncVarList.clear();
[9347]84
[8623]85  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
86  {
87    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
88    {
89      if ( (*it2)->data )
90      {
91        delete [] (*it2)->data;
92        (*it2)->data = NULL;
93      }
94      delete *it2;
95    }
96
97  }
[9347]98
[8623]99  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
100  {
101    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
102    {
103      if ( (*it2)->data )
104      {
105        delete [] (*it2)->data;
106        (*it2)->data = NULL;
107      }
108      delete *it2;
109    }
110  }
[6139]111}
[5523]112
113
[6695]114
[9396]115/**
116 * creates a diff image from two states
117 * @param userId: the userid of the user where the image will be sent to
118 * @param data: the binary data array to write to
119 * @param maxLength: maximal length of the data written (length of available space in the array)
120 * @param stateId: the state id that this diff will represent
121 * @param priorityTH: the priority threshold: all syncs below this threshold won't be synchronized
122 *
123 * @todo check for permissions
124 */
[7954]125int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
126{
127  //make sure this user has his history
128  if ( sentStates.size() <= userId )
129    sentStates.resize( userId+1 );
[5547]130
[7954]131  //calculate needed memory
132  int neededSize = 0;
[5997]133
[7954]134  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
[8147]135  {
136    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
[7954]137    neededSize += (*it)->getSize();
[8147]138  }
[5997]139
[7954]140  if ( !( neededSize <= maxLength ) )
141  {
142    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
143    assert(false);
144  }
145
146  //remove older states from history than fromStateId
147  StateHistory::iterator it = sentStates[userId].begin();
148
149  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
150    it++;
151
152  if ( it != sentStates[userId].begin() )
153  {
154    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
155    {
156      if ( (*it2)->data != NULL )
157      {
158        delete [] (*it2)->data;
159        (*it2)->data = NULL;
160      }
[9347]161
[8623]162      delete *it2;
[7954]163    }
164    sentStates[userId].erase( sentStates[userId].begin(), it );
165  }
166
167  //find state to create diff from
168  StateHistoryEntry * stateFrom = NULL;
169
170  it = sentStates[userId].begin();
171  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
172    it++;
173
174  if ( it == sentStates[userId].end() )
175  {
176    StateHistoryEntry * initialEntry = new StateHistoryEntry();
177
178    initialEntry->stateId = fromStateId;
179    initialEntry->dataLength = 0;
180    initialEntry->data = NULL;
181
182    stateFrom = initialEntry;
[9347]183
[8623]184    sentStates[userId].push_back( stateFrom );
[7954]185  }
186  else
187    stateFrom = (*it);
188
[8623]189  StateHistoryEntry * stateTo = new StateHistoryEntry;
[7954]190
[8623]191  sentStates[userId].push_back( stateTo );
[9347]192
[7954]193  stateTo->stateId = stateId;
194  stateTo->dataLength = neededSize;
195  stateTo->data = new byte[ neededSize ];
196
197  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
198
199  int i = 0;
200  int n;
[9347]201
[9396]202  bool hasPermission = false;
[8623]203  bool sizeChanged = false;
[7954]204
205  // now do the actual synchronization: kick all variables to write into a common buffer
206  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
207  {
[9396]208    // DATA PERMISSIONS
209    // check if this synchronizeable has the permissions to write the data
[9347]210
[9396]211    // first check MASTER_SERVER permissions
212    if( SharedNetworkData::getInstance()->isMasterServer() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
213      hasPermission = true;
214    // now check PROXY_SERVER permissions
215    else if( SharedNetworkData::getInstance()->isProxyServer() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
216      hasPermission = true;
217    // now check OWNER permissions
218    else if( this->owner == SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
219      hasPermission = true;
220    // now check ALL permissions
221    else if( (*it)->checkPermission( PERMISSION_ALL ))
222      hasPermission = true;
223    // SPECIAL: get write permissions if i am master server and i am able to overwrite the client stuff
224    else if( SharedNetworkData::getInstance()->isMasterServer() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
225      hasPermission = true;
226    // SPECIAL: get write permissions if i am proxy server and i am able to overwrite the client stuff
227    else if( SharedNetworkData::getInstance()->isProxyServer()  && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
228      hasPermission = true;
229    else
230      hasPermission = false;
231
232
[9347]233    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
[8623]234      sizeChanged = true;
[9347]235
[8623]236    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
[7954]237    {
238      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
239      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
[9396]240      //PRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
[7954]241      stateTo->sizeList.push_back( n );
[9375]242      // this is only for very hardcore debug sessions
243      // (*it)->debug();
[7954]244      i += n;
245    }
246    else
247    {
248      for ( int j = 0; j<(*sizeIter); j++ )
249      {
250        assert( i < stateFrom->dataLength );
251        stateTo->data[i] = stateFrom->data[i];
252        i++;
253      }
254      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
255      stateTo->sizeList.push_back( (*sizeIter) );
256    }
257
258    if ( sizeIter != stateFrom->sizeList.end() )
259      sizeIter++;
260  }
261
[8147]262  if ( i != neededSize )
263  {
[9371]264    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
[8147]265    assert(false);
266  }
[7954]267
268  //write diff to data
269  for ( i = 0; i<neededSize; i++ )
270  {
271    if ( i < stateFrom->dataLength )
272      data[i] = stateTo->data[i] - stateFrom->data[i];
273    else
274      data[i] = stateTo->data[i];
275  }
276
277  return neededSize;
278}
279
[5997]280/**
[7954]281 * sets a new state out of a diff created on another host
282 * @param userId hostId of user who send me that diff
283 * @param data pointer to diff
284 * @param length length of diff
285 * @param stateId id of current state
286 * @param fromStateId id of the base state id
287 * @return number bytes read
[9396]288 *
[7954]289 * @todo check for permissions
[5997]290 */
[7954]291int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]292{
[7954]293  //make sure this user has his history
294  if ( recvStates.size() <= userId )
295    recvStates.resize( userId+1 );
296
297  //create new state
298  StateHistoryEntry * stateTo = new StateHistoryEntry();
299  stateTo->stateId = stateId;
300  stateTo->dataLength = length;
301  stateTo->data = new byte[ length ];
302
303
304  //find state to apply diff to
305  StateHistoryEntry * stateFrom = NULL;
306
[9396]307  // search the state from wich the diff is made of
[7954]308  StateHistory::iterator it = recvStates[userId].begin();
309  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
310    it++;
311
[9396]312  // if this is the first state to receive
[7954]313  if ( it == recvStates[userId].end() )
314  {
315    StateHistoryEntry * initialEntry = new StateHistoryEntry();
316
317    initialEntry->stateId = fromStateId;
318    initialEntry->dataLength = 0;
319    initialEntry->data = NULL;
320
321    stateFrom = initialEntry;
[9347]322
[8623]323    recvStates[userId].push_back( stateFrom );
[7954]324  }
[5997]325  else
[7954]326    stateFrom = (*it);
[9347]327
[9396]328
329  // apply diff
[7954]330  for ( int i = 0; i<length; i++ )
331  {
332    if ( i < stateFrom->dataLength )
333      stateTo->data[i] = stateFrom->data[i] + data[i];
334    else
335      stateTo->data[i] = data[i];
336  }
[9347]337
[7954]338  //add state to state history
339  recvStates[userId].push_back( stateTo );
[9347]340
[7954]341  int i = 0;
342  int n = 0;
343  std::list<int> changes;
[9396]344  bool hasPermission = false;
[9347]345
[9396]346  // extract the new state for every client
[7954]347  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
348  {
[9396]349    // DATA PERMISSIONS
350    // check if this synchronizeable has the permissions to write the data
351
352    // first check MASTER_SERVER permissions
353    if(  this->networkStream->isUserMasterServer( userId ) && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
354      hasPermission = true;
355    // now check PROXY_SERVER permissions
356    else if( this->networkStream->isUserProxyServer( userId )  && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
357      hasPermission = true;
358    // now check OWNER permissions
359    else if( this->owner == SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
360      hasPermission = true;
361    // now check ALL permissions
362    else if( (*it)->checkPermission( PERMISSION_ALL ))
363      hasPermission = true;
364    // SPECIAL: get write permissions if i am master server and i am able to overwrite the client stuff
365    else if( this->networkStream->isUserMasterServer( userId ) && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
366      hasPermission = true;
367    // SPECIAL: get write permissions if i am proxy server and i am able to overwrite the client stuff
368    else if( this->networkStream->isUserProxyServer( userId )  && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ))
369      hasPermission = true;
370    else
371      hasPermission = false;
372
373    // if it has the permission to write do it
374    if( hasPermission)
[7954]375    {
376      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
377      i += n;
[9377]378      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[9396]379      //PRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[7954]380      //(*it)->debug();
381      if ( (*it)->getHasChanged() )
382      {
383        changes.push_back( (*it)->getVarId() );
384      }
385    }
386    else
387    {
[9347]388//      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]389      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
[9377]390      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[7954]391      //(*it)->debug();
392      i += n;
393    }
394  }
395
396  this->varChangeHandler( changes );
[9347]397
[7954]398  return i;
[5997]399}
400
[7954]401 /**
402 * override this function to be notified on change
403 * of your registred variables.
404 * @param id id's which have changed
405 */
406void Synchronizeable::varChangeHandler( std::list<int> & id )
407{
408}
[6695]409
[5997]410/**
[7954]411 * registers a varable to be synchronized over network
412 * @param var see src/lib/network/synchronizeable_var/ for available classes
[5997]413 */
[7954]414void Synchronizeable::registerVar( SynchronizeableVar * var )
[5997]415{
[8068]416  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
[7954]417  syncVarList.push_back( var );
[5997]418}
419
420/**
[7954]421 * registers a varable to be synchronized over network
422 * return value is passed to varChangeHandler on change
423 * @param var see src/lib/network/synchronizeable_var/ for available classes
424 * @return handle passed to varChangeHandler on changes
[5997]425 */
[7954]426int Synchronizeable::registerVarId( SynchronizeableVar * var )
[5997]427{
[8068]428  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
[7954]429  syncVarList.push_back( var );
430  var->setWatched( true );
431  var->setVarId( syncVarList.size()-1 );
432  return syncVarList.size()-1;
[5997]433}
434
435/**
[7954]436 * removed user's states from memory
437 * @param userId user to clean
[5997]438 */
[7954]439void Synchronizeable::cleanUpUser( int userId )
[5997]440{
[8228]441  if ( recvStates.size() > userId )
[7954]442  {
[8228]443    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
[7954]444    {
[8228]445      if ( (*it)->data )
[8623]446      {
[8228]447        delete [] (*it)->data;
[8623]448        (*it)->data = NULL;
449      }
[9347]450
[8228]451      delete *it;
[7954]452    }
[8228]453    recvStates[userId].clear();
[7954]454  }
[9347]455
[8228]456  if ( sentStates.size() > userId )
[7954]457  {
[9347]458
[8228]459    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
[7954]460    {
[8228]461      if ( (*it)->data )
[8623]462      {
[8228]463        delete [] (*it)->data;
[8623]464        (*it)->data = NULL;
465      }
[9347]466
[8228]467      delete *it;
[7954]468    }
[8228]469    sentStates[userId].clear();
[7954]470  }
[5997]471}
[6139]472
[6341]473/**
[7954]474 * this function is called after recieving a state.
[9347]475 * @param userId
476 * @param stateId
477 * @param fromStateId
[6341]478 */
[7954]479void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
[6341]480{
[7954]481   //make sure this user has his history
482  if ( recvStates.size() <= userId )
483    recvStates.resize( userId+1 );
[9347]484
[7954]485  //remove old states
486  StateHistory::iterator it = recvStates[userId].begin();
487
488#if 0
489  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
490    it++;
491
492  if ( it != recvStates[userId].begin() )
493  {
494    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
495    {
496      if ( (*it2)->data != NULL )
497      {
498        delete [] (*it2)->data;
499        (*it2)->data = NULL;
500      }
501    }
502    recvStates[userId].erase( recvStates[userId].begin(), it );
503  }
504#endif
505
506  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
507  {
508    if ( (*it)->stateId < fromStateId )
509    {
510      StateHistory::iterator delIt = it;
511      it ++;
[9347]512
[7954]513      if ( (*delIt)->data )
[8623]514      {
[7954]515        delete [] (*delIt)->data;
[8623]516        (*delIt)->data = NULL;
517      }
518      delete *delIt;
[7954]519      recvStates[userId].erase( delIt );
[9347]520
[7954]521      continue;
522    }
523    it++;
524  }
[9347]525
[7954]526  StateHistory::iterator fromState = recvStates[userId].end();
527  StateHistory::iterator toState = recvStates[userId].end();
[9347]528
[7954]529  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
530  {
531    if ( (*it)->stateId == stateId )
532      toState = it;
533    if ( (*it)->stateId == fromStateId )
534      fromState = it;
[9347]535
[7954]536    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
537      break;
538  }
[9347]539
[7954]540  // setStateDiff was not called and i know fromStateId
541  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
542  {
543    StateHistoryEntry * entry = new StateHistoryEntry;
[9347]544
[7954]545    entry->dataLength = (*fromState)->dataLength;
546    if ( entry->dataLength > 0 )
547    {
548      entry->data = new byte[entry->dataLength];
[9347]549
[7954]550      assert( (*fromState)->data );
551      memcpy( entry->data, (*fromState)->data, entry->dataLength );
552    }
553    else
554      entry->data = NULL;
[9347]555
[7954]556    entry->sizeList = (*fromState)->sizeList;
557    entry->stateId = stateId;
[9347]558
[7954]559    recvStates[userId].push_back(entry);
560  }
[6341]561}
[6139]562
[6341]563/**
[7954]564 * this function is called after sending a state
[9347]565 * @param userId
566 * @param stateId
567 * @param fromStateId
[6341]568 */
[7954]569void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
[6341]570{
[7954]571   //make sure this user has his history
572  if ( sentStates.size() <= userId )
573    sentStates.resize( userId+1 );
574
575   //remove old states
576  StateHistory::iterator it = sentStates[userId].begin();
577
578  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
579  {
580    if ( (*it)->stateId < fromStateId )
581    {
582      StateHistory::iterator delIt = it;
583      it ++;
[9347]584
[7954]585      if ( (*delIt)->data )
[8623]586      {
[7954]587        delete [] (*delIt)->data;
[8623]588        (*delIt)->data = NULL;
589      }
590      delete *delIt;
[7954]591      sentStates[userId].erase( delIt );
[9347]592
[7954]593      continue;
594    }
595    it++;
596  }
597
[9347]598
[7954]599  StateHistory::iterator fromState = sentStates[userId].end();
600  StateHistory::iterator toState = sentStates[userId].end();
[9347]601
[7954]602  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
603  {
604    if ( (*it)->stateId == stateId )
605      toState = it;
606    if ( (*it)->stateId == fromStateId )
607      fromState = it;
[9347]608
[7954]609    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
610      break;
611  }
612
[9347]613
[7954]614  // getStateDiff was not called and i know fromStateId
615  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
616  {
617    StateHistoryEntry * entry = new StateHistoryEntry;
[9347]618
[7954]619    entry->dataLength = (*fromState)->dataLength;
620    if ( entry->dataLength > 0 )
621    {
622      entry->data = new byte[entry->dataLength];
[9347]623
[7954]624      assert( (*fromState)->data );
625      memcpy( entry->data, (*fromState)->data, entry->dataLength );
626    }
627    else
628      entry->data = NULL;
[9347]629
[7954]630    entry->sizeList = (*fromState)->sizeList;
631    entry->stateId = stateId;
[9347]632
[7954]633    sentStates[userId].push_back(entry);
634  }
[9347]635
[6341]636}
[6139]637
[6341]638
639
Note: See TracBrowser for help on using the repository browser.