Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

fixed another bug: anomality in the permissions settings. Mr Data made a full scan, investigation closed. Mr Helm, bring us out of orbit

File size: 18.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    if ( (SharedNetworkData::getInstance()->isMasterServer() || SharedNetworkData::getInstance()->isProxyServer() )
75           && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( CL_MESSAGE_MANAGER ) )
76      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
77  }
78
79  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
80  {
81    delete *it;
82  }
83  syncVarList.clear();
84
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  }
98
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  }
111}
112
113
114
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 */
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 );
130
131  //calculate needed memory
132  int neededSize = 0;
133
134  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
135  {
136    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
137    neededSize += (*it)->getSize();
138  }
139
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      }
161
162      delete *it2;
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;
183
184    sentStates[userId].push_back( stateFrom );
185  }
186  else
187    stateFrom = (*it);
188
189  StateHistoryEntry * stateTo = new StateHistoryEntry;
190
191  sentStates[userId].push_back( stateTo );
192
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;
201
202  bool hasPermission = false;
203  bool sizeChanged = false;
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  {
208    // DATA PERMISSIONS
209    // check if this synchronizeable has the permissions to write the data
210
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    PRINTF(0)("i have |%i| permission to getStateDiff %s\n", hasPermission, (*it)->getName().c_str());
233
234
235    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
236      sizeChanged = true;
237
238    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
239    {
240      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
241      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
242      //PRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
243      stateTo->sizeList.push_back( n );
244      // this is only for very hardcore debug sessions
245      // (*it)->debug();
246      i += n;
247    }
248    else
249    {
250      for ( int j = 0; j<(*sizeIter); j++ )
251      {
252        assert( i < stateFrom->dataLength );
253        stateTo->data[i] = stateFrom->data[i];
254        i++;
255      }
256      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
257      stateTo->sizeList.push_back( (*sizeIter) );
258    }
259
260    if ( sizeIter != stateFrom->sizeList.end() )
261      sizeIter++;
262  }
263
264  if ( i != neededSize )
265  {
266    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
267    assert(false);
268  }
269
270  //write diff to data
271  for ( i = 0; i<neededSize; i++ )
272  {
273    if ( i < stateFrom->dataLength )
274      data[i] = stateTo->data[i] - stateFrom->data[i];
275    else
276      data[i] = stateTo->data[i];
277  }
278
279  return neededSize;
280}
281
282/**
283 * sets a new state out of a diff created on another host
284 * @param userId hostId of user who send me that diff
285 * @param data pointer to diff
286 * @param length length of diff
287 * @param stateId id of current state
288 * @param fromStateId id of the base state id
289 * @return number bytes read
290 *
291 * @todo check for permissions
292 */
293int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
294{
295  //make sure this user has his history
296  if ( recvStates.size() <= userId )
297    recvStates.resize( userId+1 );
298
299  //create new state
300  StateHistoryEntry * stateTo = new StateHistoryEntry();
301  stateTo->stateId = stateId;
302  stateTo->dataLength = length;
303  stateTo->data = new byte[ length ];
304
305
306  //find state to apply diff to
307  StateHistoryEntry * stateFrom = NULL;
308
309  // search the state from wich the diff is made of
310  StateHistory::iterator it = recvStates[userId].begin();
311  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
312    it++;
313
314  // if this is the first state to receive
315  if ( it == recvStates[userId].end() )
316  {
317    StateHistoryEntry * initialEntry = new StateHistoryEntry();
318
319    initialEntry->stateId = fromStateId;
320    initialEntry->dataLength = 0;
321    initialEntry->data = NULL;
322
323    stateFrom = initialEntry;
324
325    recvStates[userId].push_back( stateFrom );
326  }
327  else
328    stateFrom = (*it);
329
330
331  // apply diff
332  for ( int i = 0; i<length; i++ )
333  {
334    if ( i < stateFrom->dataLength )
335      stateTo->data[i] = stateFrom->data[i] + data[i];
336    else
337      stateTo->data[i] = data[i];
338  }
339
340  //add state to state history
341  recvStates[userId].push_back( stateTo );
342
343  int i = 0;
344  int n = 0;
345  std::list<int> changes;
346  bool hasPermission = false;
347
348  // extract the new state for every client
349  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
350  {
351    // DATA PERMISSIONS
352    // check if this synchronizeable has the permissions to write the data
353
354    // first check MASTER_SERVER permissions
355    if(  this->networkStream->isUserMasterServer( userId ) && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
356      hasPermission = true;
357    // now check PROXY_SERVER permissions
358    else if( this->networkStream->isUserProxyServer( userId )  && (*it)->checkPermission( PERMISSION_MASTER_SERVER ))
359      hasPermission = true;
360    // now check OWNER permissions
361    else if( this->owner == userId && (*it)->checkPermission( PERMISSION_OWNER ))
362      hasPermission = true;
363    // now check ALL permissions
364    else if( (*it)->checkPermission( PERMISSION_ALL ))
365      hasPermission = true;
366    // SPECIAL: get write permissions if im sending to a master server that does not own this sync
367    else if( this->networkStream->isUserMasterServer( userId ) && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
368      hasPermission = true;
369    // SPECIAL: get write permissions if im sending to a proxy server that does not own this sync
370    else if( this->networkStream->isUserProxyServer( userId )  && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ))
371      hasPermission = true;
372    else
373      hasPermission = false;
374
375
376    PRINTF(0)("i have |%i| permission to write %s\n", hasPermission, (*it)->getName().c_str());
377
378    // if it has the permission to write do it
379    if( hasPermission)
380    {
381      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
382      i += n;
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);
385      //(*it)->debug();
386      if ( (*it)->getHasChanged() )
387      {
388        changes.push_back( (*it)->getVarId() );
389      }
390    }
391    else
392    {
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 );
394      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
395      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
396      //(*it)->debug();
397      i += n;
398    }
399  }
400
401  this->varChangeHandler( changes );
402
403  return i;
404}
405
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}
414
415/**
416 * registers a varable to be synchronized over network
417 * @param var see src/lib/network/synchronizeable_var/ for available classes
418 */
419void Synchronizeable::registerVar( SynchronizeableVar * var )
420{
421  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
422  syncVarList.push_back( var );
423}
424
425/**
426 * registers a varable to be synchronized over network
427 * return value is passed to varChangeHandler on change
428 * @param var see src/lib/network/synchronizeable_var/ for available classes
429 * @return handle passed to varChangeHandler on changes
430 */
431int Synchronizeable::registerVarId( SynchronizeableVar * var )
432{
433  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
434  syncVarList.push_back( var );
435  var->setWatched( true );
436  var->setVarId( syncVarList.size()-1 );
437  return syncVarList.size()-1;
438}
439
440/**
441 * removed user's states from memory
442 * @param userId user to clean
443 */
444void Synchronizeable::cleanUpUser( int userId )
445{
446  if ( recvStates.size() > userId )
447  {
448    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
449    {
450      if ( (*it)->data )
451      {
452        delete [] (*it)->data;
453        (*it)->data = NULL;
454      }
455
456      delete *it;
457    }
458    recvStates[userId].clear();
459  }
460
461  if ( sentStates.size() > userId )
462  {
463
464    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
465    {
466      if ( (*it)->data )
467      {
468        delete [] (*it)->data;
469        (*it)->data = NULL;
470      }
471
472      delete *it;
473    }
474    sentStates[userId].clear();
475  }
476}
477
478/**
479 * this function is called after recieving a state.
480 * @param userId
481 * @param stateId
482 * @param fromStateId
483 */
484void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
485{
486   //make sure this user has his history
487  if ( recvStates.size() <= userId )
488    recvStates.resize( userId+1 );
489
490  //remove old states
491  StateHistory::iterator it = recvStates[userId].begin();
492
493#if 0
494  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
495    it++;
496
497  if ( it != recvStates[userId].begin() )
498  {
499    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
500    {
501      if ( (*it2)->data != NULL )
502      {
503        delete [] (*it2)->data;
504        (*it2)->data = NULL;
505      }
506    }
507    recvStates[userId].erase( recvStates[userId].begin(), it );
508  }
509#endif
510
511  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
512  {
513    if ( (*it)->stateId < fromStateId )
514    {
515      StateHistory::iterator delIt = it;
516      it ++;
517
518      if ( (*delIt)->data )
519      {
520        delete [] (*delIt)->data;
521        (*delIt)->data = NULL;
522      }
523      delete *delIt;
524      recvStates[userId].erase( delIt );
525
526      continue;
527    }
528    it++;
529  }
530
531  StateHistory::iterator fromState = recvStates[userId].end();
532  StateHistory::iterator toState = recvStates[userId].end();
533
534  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
535  {
536    if ( (*it)->stateId == stateId )
537      toState = it;
538    if ( (*it)->stateId == fromStateId )
539      fromState = it;
540
541    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
542      break;
543  }
544
545  // setStateDiff was not called and i know fromStateId
546  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
547  {
548    StateHistoryEntry * entry = new StateHistoryEntry;
549
550    entry->dataLength = (*fromState)->dataLength;
551    if ( entry->dataLength > 0 )
552    {
553      entry->data = new byte[entry->dataLength];
554
555      assert( (*fromState)->data );
556      memcpy( entry->data, (*fromState)->data, entry->dataLength );
557    }
558    else
559      entry->data = NULL;
560
561    entry->sizeList = (*fromState)->sizeList;
562    entry->stateId = stateId;
563
564    recvStates[userId].push_back(entry);
565  }
566}
567
568/**
569 * this function is called after sending a state
570 * @param userId
571 * @param stateId
572 * @param fromStateId
573 */
574void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
575{
576   //make sure this user has his history
577  if ( sentStates.size() <= userId )
578    sentStates.resize( userId+1 );
579
580   //remove old states
581  StateHistory::iterator it = sentStates[userId].begin();
582
583  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
584  {
585    if ( (*it)->stateId < fromStateId )
586    {
587      StateHistory::iterator delIt = it;
588      it ++;
589
590      if ( (*delIt)->data )
591      {
592        delete [] (*delIt)->data;
593        (*delIt)->data = NULL;
594      }
595      delete *delIt;
596      sentStates[userId].erase( delIt );
597
598      continue;
599    }
600    it++;
601  }
602
603
604  StateHistory::iterator fromState = sentStates[userId].end();
605  StateHistory::iterator toState = sentStates[userId].end();
606
607  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
608  {
609    if ( (*it)->stateId == stateId )
610      toState = it;
611    if ( (*it)->stateId == fromStateId )
612      fromState = it;
613
614    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
615      break;
616  }
617
618
619  // getStateDiff was not called and i know fromStateId
620  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
621  {
622    StateHistoryEntry * entry = new StateHistoryEntry;
623
624    entry->dataLength = (*fromState)->dataLength;
625    if ( entry->dataLength > 0 )
626    {
627      entry->data = new byte[entry->dataLength];
628
629      assert( (*fromState)->data );
630      memcpy( entry->data, (*fromState)->data, entry->dataLength );
631    }
632    else
633      entry->data = NULL;
634
635    entry->sizeList = (*fromState)->sizeList;
636    entry->stateId = stateId;
637
638    sentStates[userId].push_back(entry);
639  }
640
641}
642
643
644
Note: See TracBrowser for help on using the repository browser.