Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

the hybrid mode should work now in a very closed setup

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