OverSim
NTree.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
24 #include <NotifierConsts.h>
25 
26 #include "NTree.h"
27 
28 #include "GlobalNodeListAccess.h"
29 #include <GlobalStatistics.h>
30 #include <BootstrapList.h>
31 
33 
34 using namespace std;
35 
36 // TODO: Use standard join() for login
37 
38 // TODO: On move receive, check if sender is in member list, add
39 // TODO: On group leave, check for now-lost members, tell app to remove them
40 // TODO: On divide/collapse/etc (i.e. when deleting groups), check for lost members, tell app to remove them(?)
41 // TODO: Timeout players when no move received for longer period?
42 
43 void NTree::initializeOverlay(int stage)
44 {
45  // because of IPAddressResolver, we need to wait until interfaces are registered,
46  // address auto-assignment takes place etc.
47  if(stage != MIN_STAGE_OVERLAY) return;
48 
49  maxChildren = par("maxChildren");
50  if( maxChildren < 5 ){
51  throw new cRuntimeError("To allow a proper quad-tree, maxChildren has to be 5 or bigger");
52  }
53  AOIWidth = par("AOIWidth");
54 
55  thisNode.setKey(OverlayKey::random());
56 
57  areaDimension = par("areaDimension");
58  currentGroup = NULL;
59 
60  joinTimer = new cMessage("joinTimer");
61  pingTimer = new cMessage("pingTimer");
62  pingInterval = par("pingInterval");
63  scheduleAt( simTime() + pingInterval, pingTimer );
64 
65  // FIXME: Use standard baseOverlay::join()
66  changeState( INIT );
67 
68  // statistics
69  joinsSend = 0;
70  joinBytes = 0;
71  joinTimeout = 0;
72 
73  divideCount = 0;
74  collapseCount = 0;
75 
76  treeMaintenanceMessages = 0;
77  treeMaintenanceBytes = 0;
78 
79  movesSend = 0;
80  moveBytes = 0;
81 
82  WATCH_MAP( ntreeNodes );
83  WATCH_LIST( groups );
84 }
85 
87 {
88  if( state == SHUTDOWN ){
89  return false;
90  }
91  // delegate messages
92  RPC_SWITCH_START( msg )
93  RPC_DELEGATE( NTreeJoin, handleJoinCall );
94  RPC_DELEGATE( NTreePing, handlePingCall );
95  RPC_DELEGATE( NTreeDivide, handleDivideCall );
97 
98  return RPC_HANDLED;
99 
100 }
101 
103  cPolymorphic* context, int rpcId,
104  simtime_t rtt)
105 {
106  if( state == SHUTDOWN ){
107  return;
108  }
109  RPC_SWITCH_START(msg);
110  RPC_ON_RESPONSE( NTreeJoin ) {
111  EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
112  << " (" << thisNode.getKey().toString(16) << ")]\n"
113  << " Received a NTreeJoin RPC Response: id=" << rpcId << "\n"
114  << " msg=" << *_NTreeJoinResponse << " rtt=" << rtt
115  << endl;
116  handleJoinResponse( _NTreeJoinResponse );
117  break;
118  }
119  RPC_ON_RESPONSE( NTreePing ) {
120  EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
121  << " (" << thisNode.getKey().toString(16) << ")]\n"
122  << " Received a NTreePing RPC Response: id=" << rpcId << "\n"
123  << " msg=" << *_NTreePingResponse << " rtt=" << rtt
124  << endl;
125  handlePingResponse( _NTreePingResponse, dynamic_cast<NTreePingContext*>(context) );
126  break;
127  }
128  RPC_ON_RESPONSE( NTreeDivide ) {
129  EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
130  << " (" << thisNode.getKey().toString(16) << ")]\n"
131  << " Received a NTreeDivide RPC Response: id=" << rpcId << "\n"
132  << " msg=" << *_NTreeDivideResponse << " rtt=" << rtt
133  << endl;
134  handleDivideResponse( _NTreeDivideResponse, check_and_cast<NTreeGroupDivideContextPtr*>(context)->ptr );
135  delete context;
136  break;
137  }
138  RPC_SWITCH_END( );
139 }
140 
142  const TransportAddress &dest,
143  cPolymorphic* context, int rpcId,
144  const OverlayKey &destKey)
145 {
146  if( state == SHUTDOWN ){
147  return;
148  }
149  RPC_SWITCH_START(msg)
150  RPC_ON_CALL( NTreePing ) {
151  EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
152  << " (" << thisNode.getKey().toString(16) << ")]\n"
153  << " Ping RPC Call timed out: id=" << rpcId << "\n"
154  << " msg=" << *_NTreePingCall
155  << " oldNode=" << dest
156  << endl;
157  handlePingCallTimeout( _NTreePingCall, dest, dynamic_cast<NTreePingContext*>(context) );
158  break;
159  }
160  RPC_ON_CALL( NTreeJoin ) {
161  EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
162  << " (" << thisNode.getKey().toString(16) << ")]\n"
163  << " Join RPC Call timed out: id=" << rpcId << "\n"
164  << " msg=" << *_NTreeJoinCall
165  << " oldNode=" << dest
166  << endl;
167  handleJoinCallTimeout( _NTreeJoinCall, dest );
168  break;
169  }
170  RPC_ON_CALL( NTreeDivide ) {
171  EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
172  << " (" << thisNode.getKey().toString(16) << ")]\n"
173  << " Ping RPC Call timed out: id=" << rpcId << "\n"
174  << " msg=" << *_NTreeDivideCall
175  << " oldNode=" << dest
176  << endl;
177  handleDivideCallTimeout( _NTreeDivideCall, dest, check_and_cast<NTreeGroupDivideContextPtr*>(context)->ptr );
178  delete context;
179  break;
180  }
181  RPC_SWITCH_END( )
182 
183 }
184 
186 {
187  if( state == SHUTDOWN ){
188  delete msg;
189  return;
190  }
191  if( NTreeMoveMessage* moveMsg = dynamic_cast<NTreeMoveMessage*>(msg) ){
192  handleMoveMessage( moveMsg );
193  delete moveMsg;
194  } else if( NTreeGroupAddMessage* addMsg = dynamic_cast<NTreeGroupAddMessage*>(msg) ){
195  handleAddMessage( addMsg );
196  delete addMsg;
197  } else if( NTreeGroupDeleteMessage* deleteMsg = dynamic_cast<NTreeGroupDeleteMessage*>(msg) ){
198  handleDeleteMessage( deleteMsg );
199  delete deleteMsg;
200  } else if( NTreeLeaveMessage* leaveMsg = dynamic_cast<NTreeLeaveMessage*>(msg) ){
201  handleLeaveMessage( leaveMsg );
202  delete leaveMsg;
203  } else if( NTreeCollapseMessage* collapseMsg = dynamic_cast<NTreeCollapseMessage*>(msg) ){
204  handleCollapseMessage( collapseMsg );
205  delete collapseMsg;
206  } else if( NTreeReplaceNodeMessage* replaceMsg = dynamic_cast<NTreeReplaceNodeMessage*>(msg) ){
207  handleReplaceMessage( replaceMsg );
208  delete replaceMsg;
209  } else if( NTreeTakeOverMessage* takeMsg = dynamic_cast<NTreeTakeOverMessage*>(msg) ){
210  handleTakeOverMessage( takeMsg );
211  delete takeMsg;
212  }
213 }
214 
215 void NTree::handleTimerEvent(cMessage* msg)
216 {
217  if( state == SHUTDOWN ){
218  return;
219  }
220  if( msg == joinTimer ) {
221  // send a fake ready message to app to get initial position
222  CompReadyMessage* msg = new CompReadyMessage("fake READY");
223  msg->setReady(true);
224  msg->setComp(getThisCompType());
225  send( msg, "appOut");
226  // send initial AOI size to the application
227  GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
228  gameMsg->setCommand(RESIZE_AOI);
229  gameMsg->setAOIsize(AOIWidth);
230  send( gameMsg, "appOut");
231  } else if( msg == pingTimer ){
232  pingNodes();
233  checkParentTimeout();
234  scheduleAt( simTime() + pingInterval, pingTimer );
235  }
236 }
237 
238 void NTree::handleAppMessage(cMessage* msg)
239 {
240  if( GameAPIPositionMessage *posMsg = dynamic_cast<GameAPIPositionMessage*>(msg) ) {
241  if( state == READY ) {
242  handleMove( posMsg );
243  } else if ( state == JOIN ) {
244  // We are not connected to the overlay, inform app
245  CompReadyMessage* msg = new CompReadyMessage("Overlay not READY!");
246  msg->setReady(false);
247  msg->setComp(getThisCompType());
248  send( msg, "appOut");
249  } else if ( state == INIT ) {
250  // This is only called for the first MOVE message
251  TransportAddress bootstrapNode = bootstrapList->getBootstrapNode();
252  if( bootstrapNode.isUnspecified() ){
253  NTreeGroup grp(Vector2D(areaDimension/2,areaDimension/2), areaDimension);
254  grp.leader = thisNode;
255  grp.members.insert(thisNode);
256  groups.push_front(grp);
257 
258  NTreeScope initialScope(Vector2D(areaDimension/2,areaDimension/2), areaDimension);
259  NTreeNode root(initialScope);
260  root.group = &groups.front();
261  ntreeNodes.insert(make_pair(initialScope,root));
262  changeState( READY );
263  } else {
264  // Trigger login
265  changeState( JOIN );
266  position = posMsg->getPosition();
267  NTreeJoinCall* joinMsg = new NTreeJoinCall("Login");
268  joinMsg->setPosition( position );
269  joinMsg->setBitLength( NTREEJOINCALL_L(joinMsg) );
270  sendUdpRpcCall( bootstrapNode, joinMsg );
271  }
272 
273  setBootstrapedIcon();
274 
275  }
276  delete msg;
277  }
278 }
279 
280 
282 {
283  // Check if we know the group
284  std::list<NTreeGroup>::iterator grpIt = findGroup( joinCall->getPosition() );
285  if( grpIt != groups.end() ) {
286  // If we are leader, acknowlede Join
287  if( grpIt->leader == thisNode ) {
288  // Inform group about new member
289  NTreeGroupAddMessage* grpAdd = new NTreeGroupAddMessage("New group member");
290  grpAdd->setPlayer( joinCall->getSrcNode() );
291  grpAdd->setOrigin( grpIt->scope.origin );
292  grpAdd->setBitLength( NTREEADD_L(grpAdd) );
293 
294  RECORD_STATS(
295  treeMaintenanceMessages += grpIt->members.size();
296  treeMaintenanceBytes += grpIt->members.size()*grpAdd->getByteLength();
297  );
298  sendToGroup( *grpIt, grpAdd );
299 
300  grpIt->members.insert( joinCall->getSrcNode() );
301  // Acknowledge Join, send information about group
302  NTreeJoinResponse* joinResp = new NTreeJoinResponse("Join ACK");
303  joinResp->setOrigin( grpIt->scope.origin );
304  joinResp->setSize( grpIt->scope.size );
305  joinResp->setMembersArraySize( grpIt->members.size() );
306  unsigned int i = 0;
307  for( std::set<NodeHandle>::iterator it = grpIt->members.begin(); it != grpIt->members.end(); ++it ) {
308  joinResp->setMembers( i, *it );
309  ++i;
310  }
311  joinResp->setBitLength( NTREEJOINRESPONSE_L(joinResp) );
312  sendRpcResponse( joinCall, joinResp );
313 
314  // If group is to big, divide group
315  if( grpIt->members.size() > maxChildren && !grpIt->dividePending && grpIt->scope.size > 2*AOIWidth ){
316  EV << "[NTree::handleJoinCall() @ " << thisNode.getIp()
317  << " (" << thisNode.getKey().toString(16) << ")]\n"
318  << " Group got too big. Trying to divide group\n";
319  grpIt->dividePending = true;
320  std::map<NTreeScope,NTreeNode>::iterator nit = ntreeNodes.find( grpIt->scope );
321  if( nit == ntreeNodes.end() ){
322  EV << " Host is leader of a group, but not NTreeNode of that group.\n"
323  << " This should not happen. Dropping group\n";
324  if( currentGroup == &(*grpIt) ){
325  currentGroup = NULL;
326  }
327  groups.erase( grpIt );
328  return;
329  }
330  EV << " Sending divide calls\n";
331  NTreeDivideCall* divideCall = new NTreeDivideCall("Divide Group");
332  divideCall->setOrigin( nit->second.scope.origin );
333  divideCall->setSize( nit->second.scope.size );
334  divideCall->setBitLength( NTREEDIVIDECALL_L(divideCall) );
335 
337  divideContext->nodeScope = nit->second.scope;
338 
339  // select 4 random members of the group to become leader of subgroup
340  // "lotto" algoritm so nobody gets elected twice
341  unsigned int numMembers = grpIt->members.size();
342  unsigned int numbers[numMembers];
343  for( i = 0; i < numMembers; ++i ) numbers[i] = i;
344  unsigned int upperbound = numMembers;
345  for (i = 0; i < 4; ++i)
346  {
347  upperbound--;
348  unsigned int index = intuniform(0, upperbound);
349  std::set<NodeHandle>::iterator newChild = grpIt->members.begin();
350  std::advance( newChild, numbers[index] );
351 
352  if( *newChild == thisNode ) { // don't select myself
353  --i;
354  } else {
355  NTreeDivideCall* msg = divideCall->dup();
356  msg->setQuadrant( i );
357  EV << " ==> " << (TransportAddress) *newChild << "\n";
359  contextPtr->ptr = divideContext;
360  sendUdpRpcCall( *newChild, msg, contextPtr);
361  RECORD_STATS(
362  treeMaintenanceMessages++;
363  treeMaintenanceBytes += msg->getByteLength();
364  );
365  }
366 
367  swap(numbers[index], numbers[upperbound]);
368  }
369  delete divideCall;
370  }
371 
372  } else {
373  // forward join to leader
374  sendMessageToUDP( grpIt->leader, joinCall );
375  }
376  return;
377  }
378  // We don't know the group, forward join via the NTree
379  routeViaNTree( joinCall->getPosition(), joinCall, true );
380 }
381 
383 {
384  EV << "[NTree::handleJoinResponse() @ " << thisNode.getIp()
385  << " (" << thisNode.getKey().toString(16) << ")]\n"
386  << " JOIN ACK for group " << joinResp->getOrigin()
387  << "-" << joinResp->getSize() << "\n";
388  std::list<NTreeGroup>::iterator git = findGroup( joinResp->getOrigin(), joinResp->getSize() );
389  // Check for conflicting groups
390  NTreeScope groupScope( joinResp->getOrigin(), joinResp->getSize() );
391  for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
392  if( it != git && (it->isInScope( groupScope.origin ) || groupScope.contains( it->scope.origin ) )){
393  // Oops, conflicting group found. joinResp is probably outdated
394  EV << " Conflicting group found. Ignoring JOIN ACK\n";
395 
396  // if our login resulted in a divide, and we got the divide earlier that the ack,
397  // we missed to update our state. fixing.
398  if( state != READY ){
399  changeState( READY );
400  }
401  return;
402  }
403  }
404 
405  // if group already known, clear member list (new member list will be taken from message)
406  if( git != groups.end() ){
407  if( git->leader != thisNode ) {
408  EV << " Group already known. Refreshing member list\n";
409  git->members.clear();
410  } else {
411  // We are leader of the already known group. Something's fishy, ignore join
412  EV << " Group already known; and I'm leader of that group. Ignoring ACK\n";
413  return;
414  }
415 
416  } else {
417  // Else create new group
418  NTreeGroup grp(joinResp->getOrigin(), joinResp->getSize());
419  groups.push_front(grp);
420  git = groups.begin();
421  }
422 
423  // Fill in member list and leader of the group from message
424  git->leader = joinResp->getSrcNode();
425  for( unsigned int i = 0; i < joinResp->getMembersArraySize(); ++i ){
426  git->members.insert( joinResp->getMembers(i) );
427  }
428 
429  // If we were still joining the overlay, we are now ready to go
430  if( state != READY ){
431  changeState( READY );
432  }
433 }
434 
435 
437 {
438  if( state != READY ){
439  EV << " Overlay not ready. Trying to re-join overlay\n";
440  changeState( INIT );
441  }
442  joinTimeout++;
443  // TODO: Other cases when re-try is useful?
444 }
445 
447 {
448  position = posMsg->getPosition();
449  NTreeMoveMessage* moveMsg = new NTreeMoveMessage("MOVE");
450  moveMsg->setPlayer( thisNode );
451  moveMsg->setPosition( position );
452  moveMsg->setBitLength( NTREEMOVE_L(moveMsg) );
453 
454  // Send to old group
455  if( currentGroup ){
456  sendToGroup( *currentGroup, moveMsg, true);
457  RECORD_STATS(
458  movesSend += currentGroup->members.size();
459  moveBytes += moveMsg->getByteLength() * currentGroup->members.size();
460  globalStatistics->addStdDev( "NTree: Area size", currentGroup->scope.size );
461  );
462  }
463 
464  // Find group for new position
465  if( !currentGroup || !currentGroup->isInScope( position ) ){
466  std::list<NTreeGroup>::iterator it = findGroup( position );
467  if( it != groups.end() ) {
468  sendToGroup( *it, moveMsg, true );
469  currentGroup = &(*it);
470  RECORD_STATS(
471  movesSend += currentGroup->members.size();
472  moveBytes += moveMsg->getByteLength() * currentGroup->members.size();
473  );
474  } else {
475  EV << "[NTree::handleMove() @ " << thisNode.getIp()
476  << " (" << thisNode.getKey().toString(16) << ")]\n"
477  << "WARNING: no group for new position. Some updates may get lost!\n";
478  joinGroup( position );
479  }
480  }
481 
482  delete moveMsg;
483 
484  if( currentGroup ){
485  // Join new groups in our AoI and leave groups outside the AoI
486  NTreeScope& scope = currentGroup->scope;
487  NTreeScope area(Vector2D(areaDimension/2.0,areaDimension/2.0),areaDimension);
488  Vector2D aoiRight(AOIWidth/2.0, 0);
489  Vector2D aoiTop(0, AOIWidth/2.0);
490 
491  Vector2D groupRight(scope.size/2.0 +1, 0);
492  Vector2D groupTop(0, scope.size/2.0 +1);
493 
494  if(area.contains( position + aoiRight )) joinGroup(position + aoiRight);
495  if(area.contains( position - aoiRight )) joinGroup(position - aoiRight);
496  if(area.contains( position + aoiTop )) joinGroup(position + aoiTop);
497  if(area.contains( position - aoiTop )) joinGroup(position - aoiTop);
498  if(area.contains( position + (aoiRight + aoiTop)/sqrt(2))) joinGroup(position + (aoiRight + aoiTop)/sqrt(2));
499  if(area.contains( position + (aoiRight - aoiTop)/sqrt(2))) joinGroup(position + (aoiRight - aoiTop)/sqrt(2));
500  if(area.contains( position - (aoiRight + aoiTop)/sqrt(2))) joinGroup(position - (aoiRight + aoiTop)/sqrt(2));
501  if(area.contains( position - (aoiRight - aoiTop)/sqrt(2))) joinGroup(position - (aoiRight - aoiTop)/sqrt(2));
502 
503  if( scope.contains( position + aoiRight )) leaveGroup( scope.origin + groupRight );
504  if( scope.contains( position - aoiRight )) leaveGroup( scope.origin - groupRight );
505  if( scope.contains( position + aoiTop )) leaveGroup( scope.origin + groupTop );
506  if( scope.contains( position - aoiTop )) leaveGroup( scope.origin - groupTop );
507  if( scope.contains( position + (aoiRight + aoiTop)/sqrt(2))) leaveGroup( scope.origin + groupRight + groupTop);
508  if( scope.contains( position + (aoiRight - aoiTop)/sqrt(2))) leaveGroup( scope.origin + groupRight - groupTop);
509  if( scope.contains( position - (aoiRight + aoiTop)/sqrt(2))) leaveGroup( scope.origin - groupRight + groupTop);
510  if( scope.contains( position - (aoiRight - aoiTop)/sqrt(2))) leaveGroup( scope.origin - groupRight - groupTop);
511  }
512 }
513 
515 {
516  std::list<NTreeGroup>::iterator it = findGroup( addMsg->getOrigin() );
517  if( it == groups.end() ){
518  EV << "[NTree::handleAddMessage() @ " << thisNode.getIp()
519  << " (" << thisNode.getKey().toString(16) << ")]\n"
520  << " Received add message for unknown group scope=" << addMsg->getOrigin() << "\n";
521  return;
522  }
523  EV << "[NTree::handleAddMessage() @ " << thisNode.getIp()
524  << " (" << thisNode.getKey().toString(16) << ")]\n"
525  << " Received add message for group scope=" << addMsg->getOrigin() << "\n"
526  << " Player=" << addMsg->getPlayer().getKey().toString(16) << "\n";
527  it->members.insert( addMsg->getPlayer() );
528 }
529 
531 {
532  std::list<NTreeGroup>::iterator it = findGroup( deleteMsg->getOrigin(), deleteMsg->getSize() );
533  // Group already deleted
534  if( it == groups.end() ) return;
535 
536  // Check if I believe to own the group
537  // In that case, delete the corresponding node
538  ntreeNodes.erase( it->scope );
539 
540  // Join new sub-group
541  if( it->isInScope(position) ){
542  NTreeJoinCall* joinCall = new NTreeJoinCall("JOIN GROUP");
543  joinCall->setPosition(position);
544  joinCall->setBitLength( NTREEJOINCALL_L(joinCall) );
545  RECORD_STATS(
546  joinsSend++;
547  joinBytes += joinCall->getByteLength();
548  );
549  sendMessage( deleteMsg->getNewChild( it->scope.origin.getQuadrant( position )), joinCall);
550  }
551 
552  // delete group
553  if( currentGroup == &(*it) ) currentGroup = NULL;
554  groups.erase( it );
555 }
556 
558 {
559  std::list<NTreeGroup>::iterator it = findGroup( leaveMsg->getPosition() );
560  if( it != groups.end() ){
561  it->members.erase( leaveMsg->getPlayer() );
562  }
563 
564  // If player not otherwise known
565  for( it = groups.begin(); it != groups.end(); ++it ){
566  if( it->members.find( leaveMsg->getPlayer() ) != it->members.end() ){
567  return;
568  }
569  }
570 
571  // Inform app
572  GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_DELETE");
573  gameMsg->setCommand(NEIGHBOR_UPDATE);
574  gameMsg->setRemoveNeighborArraySize(1);
575  gameMsg->setRemoveNeighbor(0, leaveMsg->getPlayer() );
576  send(gameMsg, "appOut");
577 }
578 
580 {
581  EV << "[NTree::handleCollapseMessage() @ " << thisNode.getIp()
582  << " (" << thisNode.getKey().toString(16) << ")]\n"
583  << " Got collapse message for group " << collapseMsg->getOrigin() << "\n";
584 
585  std::map<NTreeScope,NTreeNode>::iterator it = findNTreeNode( collapseMsg->getOrigin(), collapseMsg->getSize() );
586  if( it != ntreeNodes.end() ){
587  if( it->second.group ){
588  EV << " Informing group\n";
589  // leaf, inform group
590  NTreeGroupDeleteMessage* delMsg = new NTreeGroupDeleteMessage("Delete Group due to collapse");
591  delMsg->setOrigin( collapseMsg->getOrigin() );
592  delMsg->setSize( collapseMsg->getSize() );
593  for( unsigned int i = 0; i < 4; ++i ){
594  delMsg->setNewChild( i, collapseMsg->getPlayer() );
595  }
596  delMsg->setBitLength( NTREEDELETE_L(delMsg) );
597  RECORD_STATS(
598  treeMaintenanceMessages += it->second.group->members.size();
599  treeMaintenanceBytes += it->second.group->members.size()*delMsg->getByteLength();
600  );
601  sendToGroup( *it->second.group, delMsg );
602  // delete group
603  if( currentGroup && *currentGroup == *it->second.group ){
604  currentGroup = NULL;
605  }
606  groups.remove( *it->second.group );
607 
608  } else {
609  // node, inform children
610  EV << " Informing children\n";
611  for( unsigned int i = 0; i < 4; ++i ){
612  EV << " ==> " << it->second.children[i] << "\n";
613  collapseMsg->setOrigin( it->second.scope.getSubScope(i).origin );
614  collapseMsg->setSize( it->second.scope.getSubScope(i).size );
615  RECORD_STATS(
616  treeMaintenanceMessages++;
617  treeMaintenanceBytes += collapseMsg->getByteLength();
618  );
619  sendMessage( it->second.children[i], collapseMsg->dup() );
620  }
621  }
622  // delete node
623  ntreeNodes.erase( it );
624  }
625 }
626 
628 {
629  // Inform app
630  GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
631  gameMsg->setCommand(NEIGHBOR_UPDATE);
632 
633  gameMsg->setAddNeighborArraySize(1);
634  gameMsg->setNeighborPositionArraySize(1);
635 
636  gameMsg->setAddNeighbor(0, moveMsg->getPlayer() );
637  gameMsg->setNeighborPosition(0, moveMsg->getPosition() );
638  send(gameMsg, "appOut");
639  RECORD_STATS(
640  globalStatistics->addStdDev(
641  "NTree: MoveDelay",
642  SIMTIME_DBL(simTime()) - SIMTIME_DBL(moveMsg->getCreationTime())
643  );
644  );
645 }
646 
648 {
649  if( NTreeNodePingCall* nodePing = dynamic_cast<NTreeNodePingCall*>(pingCall) ){
650  // node Ping
651  // compute my scope
652  NTreeScope origScope( pingCall->getOrigin(), pingCall->getSize() );
653  NTreeScope myScope;
654  myScope = origScope.getSubScope( nodePing->getQuadrant() );
655 
656  std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( myScope );
657  if( it != ntreeNodes.end() ){
658  // TODO: save parentParent?
659 
660  if( nodePing->getParent().isUnspecified() ) it->second.parentIsRoot = true;
661  for( unsigned int i = 0; i < 4; ++i ){
662  it->second.siblings[i] = nodePing->getSiblings(i);
663  }
664  it->second.lastPing = simTime();
665 
666  // Answer ping
667  NTreeNodePingResponse* nodeResp = new NTreeNodePingResponse("PONG");
668  if( it->second.group ){
669  // leaf
670  nodeResp->setAggChildCount( it->second.group->members.size() );
671  nodeResp->setMembersArraySize( it->second.group->members.size() );
672  unsigned int i = 0;
673  for( std::set<NodeHandle>::iterator childIt = it->second.group->members.begin();
674  childIt != it->second.group->members.end(); ++childIt ){
675 
676  nodeResp->setMembers( i++, *childIt );
677  }
678  } else {
679  // ordinary node
680  unsigned int aggChildCount = 0;
681  nodeResp->setMembersArraySize( 4 );
682  for( unsigned int i = 0; i < 4; ++i ){
683  aggChildCount += it->second.aggChildCount[i];
684  nodeResp->setMembers( i, it->second.children[i] );
685  }
686  nodeResp->setAggChildCount( aggChildCount );
687  }
688  nodeResp->setBitLength( NTREENODEPINGRESPONSE_L(nodeResp) );
689  sendRpcResponse( nodePing, nodeResp );
690  } else {
691  delete pingCall;
692  }
693  } else {
694  // Group ping
695  std::list<NTreeGroup>::iterator it = findGroup( pingCall->getOrigin(), pingCall->getSize() );
696  if( it != groups.end() ){
697  // TODO: save parentParent
698 
699  }
700  // Answer ping
701  NTreePingResponse* pingResp = new NTreePingResponse("PONG");
702  pingResp->setBitLength( NTREEPINGRESPONSE_L(pingResp) );
703  sendRpcResponse( pingCall, pingResp );
704  }
705 
706 }
707 
709 {
710  if( NTreeNodePingResponse* nodePing = dynamic_cast<NTreeNodePingResponse*>(pingResp) ){
711  std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
712  if( it != ntreeNodes.end() && !it->second.group){
713  // If child found, update children info in node
714  if( it->second.children[context->quadrant] == nodePing->getSrcNode() ){
715  it->second.aggChildCount[context->quadrant] = nodePing->getAggChildCount();
716  it->second.childChildren[context->quadrant].clear();
717  for( unsigned int ii = 0; ii < nodePing->getMembersArraySize(); ++ii ){
718  it->second.childChildren[context->quadrant].insert( nodePing->getMembers( ii ) );
719  }
720 
721  // Collapse tree if aggChildCount is too low
722  unsigned int aggChildCount = 0;
723  for( unsigned int i = 0; i < 4; ++i ){
724  if( !it->second.aggChildCount[i] ) {
725  aggChildCount = maxChildren;
726  break;
727  }
728 
729  aggChildCount += it->second.aggChildCount[i];
730  }
731  if( aggChildCount*2 < maxChildren ){
732  collapseTree( it );
733  }
734  } else {
735  // child not found
736  // TODO: what to do now?
737  }
738  }
739  }
740  delete context;
741 }
742 
744 {
745  if( context ){
746  std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
747  if( it != ntreeNodes.end() && !it->second.group){
748  // If child found, replace it
749  if( oldNode == it->second.children[context->quadrant ]){
750  NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace failed node");
751  replaceMsg->setOrigin( context->nodeScope.getSubScope(context->quadrant).origin );
752  replaceMsg->setSize( context->nodeScope.getSubScope(context->quadrant).size );
753  replaceMsg->setParent( thisNode );
754  replaceMsg->setOldNode( oldNode );
755  replaceMsg->setIsLeaf( it->second.childChildren[context->quadrant].size() != 4 ||
756  (it->second.childChildren[context->quadrant].size() == it->second.aggChildCount[context->quadrant]) );
757  replaceMsg->setChildrenArraySize( it->second.childChildren[context->quadrant].size() );
758  unsigned int i = 0;
759  for( std::set<NodeHandle>::iterator cit = it->second.childChildren[context->quadrant].begin();
760  cit != it->second.childChildren[context->quadrant].end(); ++cit ){
761  replaceMsg->setChildren( i, *cit );
762  ++i;
763  }
764  replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
765 
766  // Find node to replace failed node
767  std::set<NodeHandle> invalidNodes;
768  invalidNodes.insert( thisNode );
769  if( !it->second.parent.isUnspecified() ){
770  invalidNodes.insert( it->second.parent );
771  }
772  if( !replaceMsg->getIsLeaf() ) {
773  for( unsigned int i = 0; i < 4; ++i ){
774  invalidNodes.insert( replaceMsg->getChildren(i) );
775  }
776  }
777  const NodeHandle& dest = getRandomNode( invalidNodes );
778  RECORD_STATS(
779  treeMaintenanceMessages++;
780  treeMaintenanceBytes += replaceMsg->getByteLength();
781  );
782  sendMessage(dest, replaceMsg );
783  }
784  }
785  delete context;
786  } else {
787  // Group ping. Simple delete node from all groups
788  for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
789  // we have to search the group members manually, as we only have a TransportAddress to compare
790  for( std::set<NodeHandle>::iterator mit = it->members.begin(); mit != it->members.end(); ++mit ){
791  if( oldNode == *mit ){
792  NTreeLeaveMessage* leaveMsg = new NTreeLeaveMessage("Failed member");
793  leaveMsg->setPlayer( *mit );
794  leaveMsg->setPosition( it->scope.origin );
795  leaveMsg->setBitLength( NTREELEAVE_L(leaveMsg) );
796  sendToGroup( *it, leaveMsg );
797 
798  it->members.erase( mit );
799  break;
800  }
801  }
802  }
803  }
804 }
805 
807 {
808  EV << "[NTree::handleDivide() @ " << thisNode.getIp()
809  << " (" << thisNode.getKey().toString(16) << ")]\n";
810  std::list<NTreeGroup>::iterator it = findGroup( divideCall->getOrigin(), divideCall->getSize() );
811  if( it == groups.end() ){
812  EV << " Received divide message for unknown group scope=" << divideCall->getOrigin() << "\n";
813  } else {
814  EV << " Divide group " << it->scope << "\n";
815  }
816 
817  // Calculate new scope
818  NTreeScope oldScope(divideCall->getOrigin(), divideCall->getSize() );
819  NTreeScope newScope = oldScope.getSubScope( divideCall->getQuadrant() );
820 
821  // If we own the node that is beeing divided, something went wrong
822  // However, ther is nothing we can do about it except removing the offending node
823  // Sombody obviously took over without us noticing
824  ntreeNodes.erase( oldScope );
825 
826  // Create new group, delete old group
827  NTreeGroup newGroup(newScope);
828  newGroup.leader = thisNode;
829  newGroup.members.insert(thisNode);
830  groups.push_front(newGroup);
831  if( it != groups.end() ){
832  if( currentGroup == &(*it) ){
833  currentGroup = &groups.front();
834  }
835  groups.erase( it );
836  }
837 
838  // Create new ntreeNode
839  NTreeNode newNode(newScope);
840  newNode.parent = divideCall->getSrcNode();
841  newNode.group = &groups.front();
842  ntreeNodes.insert(make_pair(newScope,newNode));
843 
844  // Acknowledge Divide
845  NTreeDivideResponse* divideResp = new NTreeDivideResponse("Divide ACK");
846  divideResp->setQuadrant( divideCall->getQuadrant() );
847  divideResp->setBitLength( NTREEDIVIDERESPONSE_L(divideResp) );
848  RECORD_STATS(
849  treeMaintenanceMessages++;
850  treeMaintenanceBytes += divideResp->getByteLength();
851  );
852  sendRpcResponse( divideCall, divideResp );
853 }
854 
856 {
857  context->newChild[ divideResp->getQuadrant() ] = divideResp->getSrcNode();
858  for( unsigned int i = 0; i < 4; ++i ){
859  if( context->newChild[i].isUnspecified() ){
860  // Some responses still missing
861  return;
862  }
863  }
864  divideNode( context );
865  delete context;
866 }
867 
869 {
870  std::set<NodeHandle> invalidNodes;
871  invalidNodes.insert( thisNode );
872  NodeHandle dest = getRandomNode( invalidNodes );
873  RECORD_STATS(
874  treeMaintenanceMessages++;
875  treeMaintenanceBytes += divideCall->getByteLength();
876  );
878  contextPtr->ptr = context;
879  sendUdpRpcCall( dest, divideCall->dup(), contextPtr );
880 }
881 
883 {
884  EV << "[NTree::handleReplaceMessage() @ " << thisNode.getIp()
885  << " (" << thisNode.getKey().toString(16) << ")]\n"
886  << " Was asked to replace " << replaceMsg->getOldNode() << " for group " << replaceMsg->getOrigin() << "\n";
887  // Create new ntreeNode
888  NTreeScope newScope( replaceMsg->getOrigin(), replaceMsg->getSize() );
889  NTreeNode newNode(newScope);
890  newNode.parent = replaceMsg->getParent();
891 
892  if( replaceMsg->getIsLeaf() ){
893  std::list<NTreeGroup>::iterator it = findGroup( replaceMsg->getOrigin(), replaceMsg->getSize() );
894  if( it == groups.end() ){
895  NTreeGroup newGrp( newScope );
896  // TODO: check for conflicting groups?
897  groups.push_front( newGrp );
898  it = groups.begin();
899  }
900  it->leader = thisNode;
901  it->members.insert( thisNode );
902  for( unsigned int i = 0; i < replaceMsg->getChildrenArraySize(); ++i ){
903  it->members.insert( replaceMsg->getChildren(i) );
904  }
905  newNode.group = &(*it);
906  } else {
907  for( unsigned int i = 0; i < 4; ++i ){
908  newNode.children[i] = replaceMsg->getChildren(i);
909  }
910  }
911 
912  ntreeNodes.insert(make_pair(newScope,newNode));
913 
914  // Inform parent+children
915  NTreeTakeOverMessage* takeMsg = new NTreeTakeOverMessage("I took over");
916  takeMsg->setPlayer( thisNode );
917  takeMsg->setOrigin( newScope.origin );
918  takeMsg->setSize( newScope.size );
919  takeMsg->setBitLength( NTREETAKEOVER_L(takeMsg) );
920 
921  sendMessage( newNode.parent, takeMsg->dup() );
922  sendMessage( replaceMsg->getOldNode(), takeMsg->dup() ); // also inform old node if is is (against expectations) still alive
923  RECORD_STATS(
924  treeMaintenanceMessages+=2;
925  treeMaintenanceBytes += 2*takeMsg->getByteLength();
926  );
927  if( newNode.group ){
928  RECORD_STATS(
929  treeMaintenanceMessages += newNode.group->members.size();
930  treeMaintenanceBytes += newNode.group->members.size()*takeMsg->getByteLength();
931  );
932  sendToGroup( *newNode.group, takeMsg );
933  } else {
934  for( unsigned int i = 0; i < 4; ++i ){
935  RECORD_STATS(
936  treeMaintenanceMessages++;
937  treeMaintenanceBytes += takeMsg->getByteLength();
938  );
939  sendMessage( newNode.children[i], takeMsg->dup() );
940  }
941  delete takeMsg;
942  }
943 
944 }
945 
947 {
948  // CHeck if group leader gets replaced
949  std::list<NTreeGroup>::iterator git = findGroup( takeMsg->getOrigin(), takeMsg->getSize() );
950  if( git != groups.end() ){
951  git->leader = takeMsg->getPlayer();
952  }
953 
954  // Check if a node gets replaced
955  NTreeScope takeScope( takeMsg->getOrigin(), takeMsg->getSize() );
956  for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
957  // Check if parent is replaced
958  if( takeMsg->getSize() == it->second.scope.size*2.0 ){
959  for( unsigned int i = 0; i < 4; ++i ){
960  if( takeScope.getSubScope(i) == it->first ){
961  it->second.parent = takeMsg->getPlayer();
962  }
963  }
964  // Else check if child is replaced
965  } else if( takeMsg->getSize()*2.0 == it->second.scope.size && !it->second.group ){
966  for( unsigned int i = 0; i < 4; ++i ){
967  if( it->first.getSubScope(i) == takeScope ){
968  it->second.children[i] = takeMsg->getPlayer();
969  }
970  }
971  } else if( it->second.scope == takeScope && takeMsg->getPlayer() != thisNode ){
972  // Uh-oh. Somebody replaced me. Yield ownership
973  ntreeNodes.erase( it );
974  return;
975  }
976  }
977 
978 }
979 
981 {
982  for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
983  // Replace me on all nodes
984  NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace me");
985  replaceMsg->setOrigin( it->second.scope.origin );
986  replaceMsg->setSize( it->second.scope.size );
987  replaceMsg->setParent( it->second.parent );
988  if( it->second.group ){
989  replaceMsg->setIsLeaf( true );
990  replaceMsg->setChildrenArraySize( it->second.group->members.size() );
991  unsigned int i = 0;
992  for( std::set<NodeHandle>::iterator mit = it->second.group->members.begin(); mit != it->second.group->members.end(); ++mit ){
993  replaceMsg->setChildren(i, *mit );
994  ++i;
995  }
996  } else {
997  replaceMsg->setIsLeaf( false );
998  replaceMsg->setChildrenArraySize( 4 );
999  for( unsigned int i = 0; i < 4; ++i ){
1000  replaceMsg->setChildren(i, it->second.children[i] );
1001  }
1002  }
1003  replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
1004 
1005  // Search random node to replace me
1006  std::set<NodeHandle> invalidNodes;
1007  invalidNodes.insert( thisNode );
1008  if( !it->second.parent.isUnspecified() ){
1009  invalidNodes.insert( it->second.parent );
1010  }
1011  if( !it->second.group ) {
1012  for( unsigned int i = 0; i < 4; ++i ){
1013  invalidNodes.insert( it->second.children[i] );
1014  }
1015  }
1016  const NodeHandle& dest = getRandomNode( invalidNodes );
1017 
1018  // Inform node of his new responsabilities
1019  RECORD_STATS(
1020  treeMaintenanceMessages++;
1021  treeMaintenanceBytes += replaceMsg->getByteLength();
1022  );
1023  sendMessage( dest, replaceMsg );
1024  }
1025  while( groups.size() ){
1026  // Leave all groups
1027  leaveGroup( groups.begin()->scope.origin, true );
1028  }
1029  // clear ntree
1030  ntreeNodes.clear();
1031 
1032  currentGroup = NULL;
1033  changeState( SHUTDOWN );
1034 }
1035 
1037 {
1038  for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
1039 
1040  unsigned int i = 0;
1041  if( it->second.group ){
1042  // Leaf
1043  NTreePingCall* pingCall = new NTreePingCall("PING");
1044  pingCall->setOrigin( it->second.scope.origin );
1045  pingCall->setSize( it->second.scope.size );
1046  pingCall->setParent( it->second.parent );
1047  pingCall->setBitLength( NTREEPINGCALL_L(pingCall) );
1048  sendToGroup( *it->second.group, pingCall );
1049  } else {
1050  NTreeNodePingCall* pingCall = new NTreeNodePingCall("PING");
1051  pingCall->setOrigin( it->second.scope.origin );
1052  pingCall->setSize( it->second.scope.size );
1053  pingCall->setParent( it->second.parent );
1054 
1055  for( i = 0; i < 4; ++i ){
1056  pingCall->setSiblings(i, it->second.children[i] );
1057  }
1058  pingCall->setBitLength( NTREENODEPINGCALL_L(pingCall) );
1059 
1060  for( i = 0; i < 4; ++i ){
1061  pingCall->setQuadrant( i );
1062  sendUdpRpcCall( it->second.children[i], pingCall->dup(), new NTreePingContext(it->second.scope, i) );
1063  }
1064  delete pingCall;
1065  }
1066 
1067  }
1068 }
1069 
1071 {
1072  // Go throup all nodes. iterator is incremented in-loop to allow deletion
1073  for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ){
1074  if( it->second.parent.isUnspecified() || (it->second.lastPing == 0) ) {
1075  ++it;
1076  continue;
1077  }
1078  if( it->second.lastPing + pingInterval + pingInterval < simTime() ){
1079  // Parent timed out
1080  EV << "[NTree::checkParentTimeout() @ " << thisNode.getIp()
1081  << " (" << thisNode.getKey().toString(16) << ")]\n"
1082  << " Parent for node" << it->second << " timed out\n";
1083  // Replace parent if parent is root. Other parents will be replaced by their parents
1084  // Also, only sibling[0] does the replacing to avoid conflicts.
1085  if( it->second.parentIsRoot ) {
1086  if( it->second.siblings[0] == thisNode ){
1087  EV << " Parent was root. Replacing him\n";
1088  NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace failed ROOT.");
1089  replaceMsg->setOrigin( Vector2D(areaDimension/2.0, areaDimension/2.0) );
1090  replaceMsg->setSize( areaDimension );
1091  replaceMsg->setIsLeaf( false );
1092  replaceMsg->setChildrenArraySize( 4 );
1093  replaceMsg->setOldNode( it->second.parent );
1094 
1095  std::set<NodeHandle> invalidNodes;
1096  for( unsigned int i = 0; i < 4; ++i ){
1097  replaceMsg->setChildren( i, it->second.siblings[i] );
1098  invalidNodes.insert( replaceMsg->getChildren(i) );
1099  }
1100  replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
1101 
1102  const NodeHandle& dest = getRandomNode( invalidNodes );
1103  RECORD_STATS(
1104  treeMaintenanceMessages++;
1105  treeMaintenanceBytes += replaceMsg->getByteLength();
1106  );
1107  sendMessage(dest, replaceMsg );
1108  }
1109  ++it;
1110  } else {
1111  // else drop node
1112  if( it->second.group ){
1113  if( currentGroup && *currentGroup == *it->second.group ){
1114  currentGroup = NULL;
1115  }
1116  groups.remove( *it->second.group );
1117  }
1118  ntreeNodes.erase( it++ );
1119  }
1120  } else {
1121  ++it;
1122  }
1123  }
1124 }
1125 
1127 {
1128  EV << "[NTree::divideNode() @ " << thisNode.getIp()
1129  << " (" << thisNode.getKey().toString(16) << ")]\n"
1130  << " Trying to divide node " << context->nodeScope << "\n";
1131  std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
1132  if( it == ntreeNodes.end() ){
1133  EV << " However, node is not in the list of known nodes\n";
1134  return;
1135  }
1136  if( !it->second.group ){
1137  EV << " However, node has no known group attached\n";
1138  return;
1139  }
1140  // Inform group members
1141  NTreeGroupDeleteMessage* delMsg = new NTreeGroupDeleteMessage("Delete Group due to divide");
1142  delMsg->setOrigin( context->nodeScope.origin );
1143  delMsg->setSize( context->nodeScope.size );
1144  delMsg->setBitLength( NTREEDELETE_L(delMsg) );
1145  for( unsigned int i = 0; i < 4; ++i ){
1146  delMsg->setNewChild(i, context->newChild[i] );
1147  }
1148  RECORD_STATS(
1149  divideCount ++;
1150  treeMaintenanceMessages+= it->second.group->members.size();
1151  treeMaintenanceBytes += it->second.group->members.size()*delMsg->getByteLength();
1152  );
1153  sendToGroup( *it->second.group, delMsg );
1154 
1155  // delete group
1156  if( currentGroup && *currentGroup == *it->second.group ){
1157  currentGroup = NULL;
1158  }
1159  groups.remove( *it->second.group );
1160  it->second.group= NULL;
1161 
1162  // add children to ntreeNode
1163  for( unsigned int i = 0; i < 4; ++i ){
1164  it->second.children[i] = context->newChild[i];
1165  }
1166 }
1167 
1168 void NTree::collapseTree( std::map<NTreeScope,NTreeNode>::iterator node )
1169 {
1170  EV << "[NTree::CollapseTree() @ " << thisNode.getIp()
1171  << " (" << thisNode.getKey().toString(16) << ")]\n"
1172  << " Collapsing tree" << node->second << "\n";
1173  // Inform children
1174  NTreeCollapseMessage* collapseMsg = new NTreeCollapseMessage("Collapse Tree");
1175  collapseMsg->setPlayer( thisNode );
1176  collapseMsg->setBitLength( NTREECOLLAPSE_L(collapseMsg) );
1177 
1178  for( unsigned int i = 0; i < 4; ++i ){
1179  collapseMsg->setOrigin( node->second.scope.getSubScope(i).origin );
1180  collapseMsg->setSize( node->second.scope.getSubScope(i).size );
1181  RECORD_STATS(
1182  treeMaintenanceMessages++;
1183  treeMaintenanceBytes += collapseMsg->getByteLength();
1184  collapseCount ++;
1185  );
1186  sendMessage( node->second.children[i], collapseMsg->dup() );
1187  // and update node
1188  node->second.children[i] = NodeHandle::UNSPECIFIED_NODE;
1189  node->second.childChildren[i].clear();
1190  node->second.aggChildCount[i] = 0;
1191  }
1192  delete collapseMsg;
1193 
1194  // create group for node
1195  NTreeGroup newGroup( node->second.scope );
1196  newGroup.leader = thisNode;
1197  newGroup.members.insert( thisNode );
1198  groups.push_front( newGroup );
1199 
1200  node->second.group = &(groups.front());
1201 }
1202 
1203 void NTree::joinGroup( Vector2D position )
1204 {
1205  std::list<NTreeGroup>::iterator grpIt = findGroup( position );
1206  if( grpIt == groups.end() ) {
1207  NTreeJoinCall* joinCall = new NTreeJoinCall("JOIN GROUP");
1208  joinCall->setPosition( position );
1209  joinCall->setBitLength( NTREEJOINCALL_L(joinCall) );
1210  RECORD_STATS(
1211  joinsSend++;
1212  joinBytes += joinCall->getByteLength();
1213  );
1214  routeViaNTree( position, joinCall );
1215  }
1216 }
1217 
1218 void NTree::leaveGroup( Vector2D position, bool force )
1219 {
1220  std::list<NTreeGroup>::iterator grpIt = findGroup( position );
1221  // Don't leave group if I'm leader of that group (except if forced)
1222  if( grpIt != groups.end() && (grpIt->leader != thisNode || force) ) {
1223  NTreeLeaveMessage* leaveMsg = new NTreeLeaveMessage("Leave Group");
1224  leaveMsg->setPlayer( thisNode );
1225  leaveMsg->setPosition( position );
1226  leaveMsg->setBitLength( NTREELEAVE_L(leaveMsg) );
1227  sendToGroup( *grpIt, leaveMsg );
1228 
1229  if( currentGroup == &(*grpIt) ){
1230  EV << "[NTree::leaveGroup() @ " << thisNode.getIp()
1231  << " (" << thisNode.getKey().toString(16) << ")]\n"
1232  << " WARNING: Leaving group " << position << "\n"
1233  << " This group is marked as current group!\n";
1234  currentGroup = NULL;
1235  }
1236  groups.erase( grpIt );
1237  }
1238 }
1239 
1240 void NTree::routeViaNTree( const Vector2D& pos, cPacket* msg, bool forward )
1241 {
1242  NodeHandle dest;
1243  if( ntreeNodes.size() ) {
1244  // Check if pos is in scope of one ntree node
1245  std::map<NTreeScope,NTreeNode>::iterator it = findNTreeNode( pos );
1246  if( it != ntreeNodes.end() ){
1247  // Forward message to appropriate child
1248  dest = it->second.getChildForPos( pos );
1249  } else {
1250  // else send to parent of highest ntreeNode
1251  dest = ntreeNodes.begin()->second.parent;
1252  }
1253  } else {
1254  // No Ntree known. Send to group leader
1255  if( currentGroup ){
1256  dest = currentGroup->leader;
1257  } else if( groups.size() ){
1258  dest = groups.begin()->leader;
1259  } else { // No group known. We have to re-join. (Even though a JOIN might still be in progress)
1260  EV << "[NTree::routeViaNTree() @ " << thisNode.getIp()
1261  << " (" << thisNode.getKey().toString(16) << ")]\n"
1262  << " No ntree node and no group known. Dropping message & re-join!\n";
1263  changeState( INIT );
1264  delete msg;
1265  return;
1266  }
1267  }
1268  if( forward && dest == thisNode ) {
1269  EV << "[NTree::routeViaNTree() @ " << thisNode.getIp()
1270  << " (" << thisNode.getKey().toString(16) << ")]\n"
1271  << " Trying to route message " << msg << " to myself\n"
1272  << " This will result in a loop. Dropping message\n";
1273  delete msg;
1274  } else {
1275  sendMessage( dest, msg, forward );
1276  }
1277 
1278 }
1279 
1280 void NTree::sendToGroup( const NTreeGroup& grp, cPacket* msg, bool keepMsg )
1281 {
1282  EV << "[NTree::sendToGroup() @ " << thisNode.getIp()
1283  << " (" << thisNode.getKey().toString(16) << ")]\n"
1284  << " Send message " << msg << "\n"
1285  << " to group scope=" << grp.scope.origin << "\n";
1286  NTree::sendToGroup( grp.members, msg, keepMsg );
1287 }
1288 
1289 void NTree::sendToGroup( const std::set<NodeHandle>& grp, cPacket* msg, bool keepMsg )
1290 {
1291  for( std::set<NodeHandle>::iterator it = grp.begin(); it != grp.end(); ++it ){
1292  sendMessage( *it, msg->dup(), false );
1293  }
1294  if (!keepMsg) delete msg;
1295 }
1296 
1297 
1298 void NTree::sendMessage(const TransportAddress& dest, cPacket* msg, bool forward)
1299 {
1300  if( dest.isUnspecified() ) {
1301  EV << "[NTree::sendMessage() @ " << thisNode.getIp()
1302  << " (" << thisNode.getKey().toString(16) << ")]\n"
1303  << " WARNING: Trying to send message " << msg
1304  << " to unspecified destination. Dropping packet!\n";
1305  delete msg;
1306  return;
1307  }
1308 
1309  // TODO: statistics?
1310  BaseCallMessage* rpc = dynamic_cast<BaseCallMessage*>(msg);
1311  if( rpc && !forward ){
1312  // Slightly evil: If an OverlayKey is set, the RPC response
1313  // may get dropped if it was forwarded (because OverSim expects
1314  // frowarding to be done with BaseRoutMessages. Which we can't do,
1315  // because we are not routing to overlay keys but to positions.
1316  // Thus, we cast the OverlayKey away.
1317  sendUdpRpcCall( TransportAddress(dest), rpc );
1318  } else {
1319  sendMessageToUDP( dest, msg );
1320  }
1321 }
1322 
1323 void NTree::changeState( int newState ) {
1324  switch( newState ){
1325  case INIT:
1326  state = INIT;
1327  if( !joinTimer->isScheduled() ) {
1328  scheduleAt( ceil(simTime() + (simtime_t) par("joinDelay")), joinTimer );
1329  }
1330  break;
1331 
1332  case READY:
1333  state = READY;
1334  setBootstrapedIcon();
1335  if( !currentGroup && groups.size() ) currentGroup = &groups.front();
1336  setOverlayReady( true );
1337  break;
1338 
1339  case JOIN:
1340  state = JOIN;
1341  setOverlayReady( false );
1342  break;
1343 
1344  case SHUTDOWN:
1345  state = SHUTDOWN;
1346  cancelAndDelete( pingTimer );
1347  pingTimer = NULL;
1348  setOverlayReady( false );
1349  break;
1350  }
1351  setBootstrapedIcon();
1352 }
1353 
1355 {
1356  if(ev.isGUI()) {
1357  if(state == READY) {
1358  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "green");
1359  getDisplayString().setTagArg("i", 1, "green");
1360  }
1361  else if(state == JOIN) {
1362  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "yellow");
1363  getDisplayString().setTagArg("i", 1, "yellow");
1364  }
1365  else {
1366  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "red");
1367  getDisplayString().setTagArg("i", 1, "red");
1368  }
1369  }
1370 }
1371 
1372 std::list<NTreeGroup>::iterator NTree::findGroup(const Vector2D& pos)
1373 {
1374  for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
1375  if( it->isInScope( pos ) ) return it;
1376  }
1377  return groups.end();
1378 }
1379 
1380 std::list<NTreeGroup>::iterator NTree::findGroup(const Vector2D& pos, double size)
1381 {
1382  for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
1383  if( it->scope.origin == pos && it->scope.size == size ) return it;
1384  }
1385  return groups.end();
1386 }
1387 
1388 std::map<NTreeScope,NTreeNode>::iterator NTree::findNTreeNode(const Vector2D& pos)
1389 {
1390  double size = areaDimension + 1;
1391  std::map<NTreeScope,NTreeNode>::iterator bestNode = ntreeNodes.end();
1392  for( std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
1393  if( it->second.isInScope( pos ) && it->second.scope.size < size ){
1394  bestNode = it;
1395  size = bestNode->second.scope.size;
1396  }
1397  }
1398  return bestNode;
1399 }
1400 
1401 std::map<NTreeScope,NTreeNode>::iterator NTree::findNTreeNode(const Vector2D& pos, double size)
1402 {
1403  return ntreeNodes.find( NTreeScope( pos, size ) );
1404 }
1405 
1406 NodeHandle NTree::getRandomNode( std::set<NodeHandle> invalidNodes )
1407 {
1408  // FIXME: This is cheating...
1409  bool found = false;
1410  NodeHandle dest;
1411  while( !found ){
1412  dest = globalNodeList->getRandomNode();
1413  found = true;
1414  for( std::set<NodeHandle>::iterator it = invalidNodes.begin(); it != invalidNodes.end(); ++it ){
1415  if( dest == *it ){
1416  found = false;
1417  break;
1418  }
1419  }
1420  }
1421  return dest;
1422 }
1423 
1425 {
1426  simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
1427  if (time < GlobalStatistics::MIN_MEASURED) return;
1428  globalStatistics->addStdDev("NTree: Joins send per second", joinsSend / time );
1429  globalStatistics->addStdDev("NTree: Join bytes send per second", joinBytes / time );
1430  globalStatistics->addStdDev("NTree: Join timeouts per second", joinTimeout / time );
1431  globalStatistics->addStdDev("NTree: Tree maintenance messages send per second", treeMaintenanceMessages / time );
1432  globalStatistics->addStdDev("NTree: Tree maintenance bytes send per second", treeMaintenanceBytes / time );
1433  globalStatistics->addStdDev("NTree: Move messages send per second", movesSend / time );
1434  globalStatistics->addStdDev("NTree: Move bytes send per second", moveBytes / time );
1435  globalStatistics->addStdDev("NTree: Tree collapsed per second", collapseCount / time );
1436  globalStatistics->addStdDev("NTree: Tree divides per second", divideCount / time );
1437 }
1438 
1440 {
1441  cancelAndDelete(joinTimer);
1442  cancelAndDelete(pingTimer);
1443 }
1444