OverSim
Vast.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 "Vast.h"
25 
27 
28 #include <NotifierConsts.h>
29 
30 #include <GlobalNodeList.h>
31 #include <GlobalStatistics.h>
32 #include <BootstrapList.h>
33 
34 void Vast::initializeOverlay(int stage)
35 {
36  // because of IPAddressResolver, we need to wait until interfaces are registered,
37  // address auto-assignment takes place etc.
38  if(stage != MIN_STAGE_OVERLAY) return;
39 
40  // fetch parameters
41  debugVoronoiOutput = par("debugVastOutput");
42  areaDimension = par("areaDimension");
43  AOI_size = par("AOIWidth");
44  joinTimeout = par("joinTimeout");
45  pingTimeout = par("pingTimeout");
46  discoveryIntervall = par("discoveryIntervall");
47  checkCriticalIntervall = par("criticalCheckIntervall");
48  criticalThreshold = par("criticalThreshold");
49  stockListSize = par("stockListSize");
50 
51  // set node key
53  thisSite.type = THIS;
55 
57 
58  // self-messages
59  join_timer = new cMessage("join_timer");
60  ping_timer = new cMessage("ping_timer");
61  sec_timer = new cMessage("sec_timer");
62  discovery_timer = new cMessage("discovery_timer");
63  checkcritical_timer = new cMessage("checkcritical_timer");
64 
65  // statistics
72  pingBytesSent = 0;
73  pongBytesSent = 0;
75  backupBytesSent = 0;
76 
79  bytesPerSecond = 0;
80  secTimerCount = 0;
81 
82  // watch some variables
83  WATCH(AOI_size);
84  WATCH(thisSite);
85  WATCH_MAP(Sites);
86  WATCH_SET(Positions);
87 
88  WATCH(joinRequestBytesSent);
90  WATCH(nodeMoveBytesSent);
91  WATCH(newNeighborsBytesSent);
92  WATCH(nodeLeaveBytesSent);
94  WATCH(pingBytesSent);
95  WATCH(pongBytesSent);
96  WATCH(discardNodeBytesSent);
97 
98  WATCH(maxBytesPerSecondSent);
99  WATCH(bytesPerSecond);
100 
101  // set initial state
102  changeState(INIT);
103  changeState(JOIN);
104 }
105 
106 void Vast::changeState(int state)
107 {
108  switch(state) {
109  case INIT: {
110  this->state = INIT;
112  cancelEvent(join_timer);
113  cancelEvent(ping_timer);
114  cancelEvent(sec_timer);
115  cancelEvent(discovery_timer);
116  cancelEvent(checkcritical_timer);
117  } break;
118  case JOIN: {
119  this->state = JOIN;
120  scheduleAt(simTime(), join_timer);
121  scheduleAt(simTime() + 1.0, sec_timer);
122  } break;
123  case READY: {
124  this->state = READY;
125  cancelEvent(join_timer);
127  scheduleAt(simTime() + pingTimeout, ping_timer);
128  if(checkCriticalIntervall > 0.0 && discoveryIntervall > 0.0) {
129  scheduleAt(simTime() + checkCriticalIntervall, checkcritical_timer);
130  scheduleAt(simTime() + discoveryIntervall, discovery_timer);
131  }
132  // tell the application we are ready
133  CompReadyMessage* readyMsg = new CompReadyMessage("OVERLAY_READY");
134  readyMsg->setReady(true);
135  readyMsg->setComp(getThisCompType());
136  sendToApp(readyMsg);
137  GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
138  gameMsg->setCommand(RESIZE_AOI);
139  gameMsg->setAOIsize(AOI_size);
140  sendToApp(gameMsg);
141  } break;
142  }
144  // debug output
145  if(debugOutput) {
146  EV << "[Vast::changeState() @ " << thisSite.addr.getIp()
147  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
148  << "VAST: Node " << thisSite.addr.getIp() << " entered ";
149  switch(state) {
150  case INIT: ev << "INIT"; break;
151  case JOIN: ev << "JOIN"; break;
152  case READY: ev << "READY"; break;
153  }
154  ev << " state." << endl;
155  }
156 }
157 
158 void Vast::handleTimerEvent(cMessage* msg)
159 {
160  if(msg->isName("join_timer")) {
161  //reset timer
162  cancelEvent(join_timer);
163  scheduleAt(simTime() + joinTimeout, msg);
164  // handle event
166  }
167  else if(msg->isName("ping_timer")) {
168  //reset timer
169  cancelEvent(ping_timer);
170  scheduleAt(simTime() + pingTimeout, msg);
171  // handle event
173  }
174  else if(msg->isName("sec_timer")) {
175  //reset timer
176  cancelEvent(sec_timer);
177  scheduleAt(simTime() + 1, msg);
178  // handle event
179  processSecTimer();
180  }
181  else if(msg->isName("checkcritical_timer")) {
182  //reset timer
183  cancelEvent(checkcritical_timer);
184  scheduleAt(simTime() + checkCriticalIntervall, msg);
185  // handle event
187  }
188  else if(msg->isName("discovery_timer")) {
189  //reset timer
190  cancelEvent(discovery_timer);
191  scheduleAt(simTime() + discoveryIntervall, msg);
192  // handle event
194  }
195 }
196 
197 void Vast::handleAppMessage(cMessage* msg)
198 {
199  if(dynamic_cast<GameAPIMessage*>(msg)) {
200  GameAPIMessage* gameAPIMsg = check_and_cast<GameAPIMessage*>(msg);
201  // debug output
202  if(debugOutput) EV << "[Vast::handleAppMessage() @ " << thisSite.addr.getIp()
203  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
204  << " Node " << thisSite.addr.getIp() << " received " << gameAPIMsg->getName() << " from application."
205  << endl;
206  switch(gameAPIMsg->getCommand()) {
207  case MOVEMENT_INDICATION: {
208  GameAPIPositionMessage* gameAPIPosMsg = check_and_cast<GameAPIPositionMessage*>(msg);
209  if(state == JOIN) {
210  handleJoin(gameAPIPosMsg);
211  delete msg;
212  }
213  else if(state == READY) {
214  handleMove(gameAPIPosMsg);
215  delete msg;
216  }
217  } break;
218  case GAMEEVENT_CHAT:
219  case GAMEEVENT_SNOW:
220  case GAMEEVENT_FROZEN:
221  handleEvent( gameAPIMsg );
222  delete msg;
223  break;
224  default: {
225  delete msg;
226  }
227  }
228  }
229  else delete msg;
230 }
231 
233 {
234  if(state == INIT) {
235  delete msg;
236  return;
237  }
238  if(dynamic_cast<VastMessage*>(msg)) {
239  VastMessage* vastMsg = check_and_cast<VastMessage*>(msg);
240  if(vastMsg->getDestKey().isUnspecified() ||
242  vastMsg->getDestKey() == thisSite.addr.getKey()) {
243  // debug output
244  if(debugOutput) EV << "[Vast::handleUDPMessage() @ " << thisSite.addr.getIp()
245  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
246  << " Node " << thisSite.addr.getIp() << " received " << vastMsg->getName() << " from " << vastMsg->getSourceNode().getIp()
247  << endl;
248  bool doUpdate = true;
249  if(state == READY) {
250  switch(vastMsg->getCommand()) {
251  case JOIN_REQUEST: {
252  handleJoinRequest(vastMsg);
253  doUpdate = false;
254  } break;
255  case NODE_MOVE: {
256  VastMoveMessage* vastMoveMsg = check_and_cast<VastMoveMessage*>(msg);
257  handleNodeMove(vastMoveMsg);
258  } break;
259  case NEW_NEIGHBORS: {
260  VastListMessage* vastListMsg = check_and_cast<VastListMessage*>(msg);
261  handleNewNeighbors(vastListMsg);
262  } break;
263  case NODE_LEAVE: {
264  VastListMessage* vastListMsg = check_and_cast<VastListMessage*>(msg);
265  handleNodeLeave(vastListMsg);
266  } break;
269  } break;
270  case BACKUP_NEIGHBORS: {
271  VastListMessage* vastListMsg = check_and_cast<VastListMessage*>(msg);
272  handleBackupNeighbors(vastListMsg);
273  } break;
274  case PING: {
275  handlePing(vastMsg);
276  } break;
277  case PONG: {
278  handlePong(vastMsg);
279  } break;
280  case DISCARD_NODE: {
281  VastDiscardMessage* vastDiscardMsg = check_and_cast<VastDiscardMessage*>(msg);
282  handleDiscardNode(vastDiscardMsg);
283  } break;
284  case VAST_EVENT: {
285  sendToApp(vastMsg->decapsulate());
286  doUpdate = false;
287  delete vastMsg;
288  } break;
289  }
290  // update timestamp
291  if(doUpdate) {
292  SiteMap::iterator itSites = Sites.find(vastMsg->getSourceNode());
293  if(itSites != Sites.end()) {
294  itSites->second->tstamp = simTime();
295  }
296  delete msg;
297  }
298  }
299  else if(state == JOIN && vastMsg->getCommand() == JOIN_ACKNOWLEDGE) {
300  VastListMessage* vastListMsg = check_and_cast<VastListMessage*>(msg);
301  handleJoinAcknowledge(vastListMsg);
302  delete msg;
303  }
304  else delete msg;
305  }
306  else {
307  sendDiscardNode(vastMsg);
308  delete msg;
309  }
310  }
311  else delete msg;
312 }
313 
314 void Vast::addNode(Vector2D p, NodeHandle node, int NeighborCount)
315 {
316  if(node != thisSite.addr) {
317  if(Sites.find(node) == Sites.end()) {
318  Site* temp_site = new Site();
319  temp_site->coord = p;
320  temp_site->addr = node;
321  temp_site->neighborCount = NeighborCount;
322 
323  Sites.insert(std::make_pair(temp_site->addr, temp_site));
324  Positions.insert(temp_site->coord);
325  }
326  else {
327  SiteMap::iterator itSites = Sites.find(node);
328  Positions.erase(itSites->second->coord);
329  itSites->second->coord = p;
330  Positions.insert(itSites->second->coord);
331  if(NeighborCount != 0) {
332  itSites->second->neighborCount = NeighborCount;
333  }
334  }
335  }
336 }
337 
339 {
340  if(node != thisSite.addr) {
341  for(StockList::iterator itTemp = Stock.begin(); itTemp != Stock.end(); ++itTemp) {
342  if(*itTemp == node) {
343  return;
344  }
345  }
346  Stock.push_front(node);
347  if(Stock.size() > stockListSize) {
348  Stock.pop_back();
349  }
350  }
351 }
352 
354 {
355  SiteMap::iterator itSites = Sites.find(node);
356  if(itSites != Sites.end()) {
357  Positions.erase(itSites->second->coord);
358  delete itSites->second;
359  Sites.erase(itSites);
360  }
361 }
362 
363 void Vast::buildVoronoi(Vector2D old_pos, Vector2D new_pos, NodeHandle enclosingCheck)
364 {
365  int sqrt_nsites = 1;
366  double xmin, xmax, ymin, ymax;
367  double deltax, deltay;
368 
369  // check wether there are any neighbors
370  if(Sites.size() == 0) return;
371 
372  xmin = xmax = thisSite.coord.x;
373  ymin = ymax = thisSite.coord.y;
374 
375  std::map<Vector2D, Site*> sortedSites;
376  sortedSites.insert(std::make_pair(thisSite.coord, &thisSite));
377 
378  for(SiteMap::iterator itTemp = Sites.begin(); itTemp != Sites.end(); ++itTemp) {
379  // determine min/max site coordinates
380  if(itTemp->second->coord.x < xmin) xmin = itTemp->second->coord.x;
381  if(itTemp->second->coord.x > xmax) xmax = itTemp->second->coord.x;
382  if(itTemp->second->coord.y < ymin) ymin = itTemp->second->coord.y;
383  if(itTemp->second->coord.y > ymax) ymax = itTemp->second->coord.y;
384  // reset all sites to UNDEF
385  itTemp->second->type = UNDEF;
386  // reset enclosing neighbors set
387  itTemp->second->enclosingSet.clear();
388  // fill sorted List
389  sortedSites.insert(std::make_pair(itTemp->second->coord, itTemp->second));
390  sqrt_nsites++;
391  }
392 
393  // needed to determine appropriate hashtable size
394  deltax = xmax - xmin;
395  deltay = ymax - ymin;
396  sqrt_nsites = (int)sqrt((double)(sqrt_nsites+4));
397 
398  // start to calculate the voronoi
399  Site *newsite, *bot, *top, *temp, *p, *v, *bottomsite;
400  Vector2D newintstar;
401  int pm;
402  Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
403  Edge *e;
404 
405  newintstar.x = newintstar.y = 0.0;
406 
407  std::map<Vector2D, Site*>::iterator itSortedSites = sortedSites.begin();
408 
409  geom.initialize(deltax, deltay, thisSite.coord, old_pos, new_pos, AOI_size);
410  heap.PQinitialize(sqrt_nsites, ymin, deltay);
411  bottomsite = itSortedSites->second;
412  ++itSortedSites;
413  edgelist.initialize(sqrt_nsites, xmin, deltax, bottomsite);
414 
415  newsite = itSortedSites->second;
416  ++itSortedSites;
417  while(true) {
418  if(!heap.PQempty()) newintstar = heap.PQ_min();
419 
420  if(newsite != NULL && (heap.PQempty() ||
421  newsite->coord.y < newintstar.y ||
422  (newsite->coord.y == newintstar.y && newsite->coord.x < newintstar.x))) {
423  lbnd = edgelist.ELleftbnd(&(newsite->coord));
424  rbnd = edgelist.ELright(lbnd);
425  bot = edgelist.rightreg(lbnd);
426  e = geom.bisect(bot, newsite);
427  bisector = edgelist.HEcreate(e, le);
428  edgelist.ELinsert(lbnd, bisector);
429  if ((p = geom.intersect(lbnd, bisector)) != NULL) {
430  heap.PQdelete(lbnd);
431  heap.PQinsert(lbnd, p, geom.dist(p, newsite));
432  }
433  lbnd = bisector;
434  bisector = edgelist.HEcreate(e, re);
435  edgelist.ELinsert(lbnd, bisector);
436  if ((p = geom.intersect(bisector, rbnd)) != NULL) heap.PQinsert(bisector, p, geom.dist(p, newsite));
437  if(itSortedSites != sortedSites.end()) {
438  newsite = itSortedSites->second;
439  ++itSortedSites;
440  }
441  else newsite = NULL;
442  }
443  else if (!heap.PQempty()) {
444  lbnd = heap.PQextractmin();
445  llbnd = edgelist.ELleft(lbnd);
446  rbnd = edgelist.ELright(lbnd);
447  rrbnd = edgelist.ELright(rbnd);
448  bot = edgelist.leftreg(lbnd);
449  top = edgelist.rightreg(rbnd);
450  v = lbnd->vertex;
451  geom.endpoint(lbnd->ELedge, lbnd->ELpm, v);
452  geom.endpoint(rbnd->ELedge, rbnd->ELpm, v);
453  edgelist.ELdelete(lbnd);
454  heap.PQdelete(rbnd);
455  edgelist.ELdelete(rbnd);
456  pm = le;
457  if (bot->coord.y > top->coord.y) {
458  temp = bot;
459  bot = top;
460  top = temp;
461  pm = re;
462  }
463  e = geom.bisect(bot, top);
464  bisector = edgelist.HEcreate(e, pm);
465  edgelist.ELinsert(llbnd, bisector);
466  geom.endpoint(e, re-pm, v);
467  if((p = geom.intersect(llbnd, bisector)) != NULL) {
468  heap.PQdelete(llbnd);
469  heap.PQinsert(llbnd, p, geom.dist(p, bot));
470  }
471  if ((p = geom.intersect(bisector, rrbnd)) != NULL) heap.PQinsert(bisector, p, geom.dist(p, bot));
472  }
473  else break;
474  }
475 
476  // process the generated edgelist
477  for(lbnd = edgelist.ELright(edgelist.ELleftend); lbnd != edgelist.ELrightend; lbnd = edgelist.ELright(lbnd)) {
478  e = lbnd -> ELedge;
479  geom.processEdge(e);
480  }
481  // process sites in order to determine our neighbors
482  for(SiteMap::iterator itTemp = Sites.begin(); itTemp != Sites.end(); ++itTemp) {
483  if(itTemp->second->innerEdge[0]) {
484  if(itTemp->second->outerEdge) {
485  itTemp->second->type |= BOUNDARY;
486  // Debug output
487  if(debugOutput)
488  EV << "[NeighborsList::buildVoronoi()]\n"
489  << " Site at [" << itTemp->second->coord.x << ", "
490  << itTemp->second->coord.y << "] is a boundary neighbor."
491  << endl;
492  }
493  else {
494  itTemp->second->type |= NEIGHBOR;
495  // Debug output
496  if(debugOutput)
497  EV << "[NeighborsList::buildVoronoi()]\n"
498  << " Site at [" << itTemp->second->coord.x << ", "
499  << itTemp->second->coord.y << "] is a neighbor."
500  << endl;
501  }
502  }
503  // Treat enclosing neighbors whose voronoi region is outside our AOI as boundary neighbors
504  if((!itTemp->second->type & NEIGHBOR) && (itTemp->second->type & ENCLOSING)) {
505  itTemp->second->type |= BOUNDARY;
506  // Debug output
507  if(debugOutput)
508  EV << "[NeighborsList::buildVoronoi()]\n"
509  << " Site at [" << itTemp->second->coord.x << ", "
510  << itTemp->second->coord.y << "] is a boundary neighbor."
511  << endl;
512  }
513  if(!itTemp->second->innerEdge[1] && itTemp->second->innerEdge[2]) {
514  itTemp->second->type |= NEW;
515  // Debug output
516  if(debugOutput)
517  EV << "[NeighborsList::buildVoronoi()]\n"
518  << " Site at [" << itTemp->second->coord.x << ", "
519  << itTemp->second->coord.y << "] is a new neighbor for site at " << new_pos.x << ":" << new_pos.y << "."
520  << endl;
521  }
522  // enhanced enclosing check
523  if(!enclosingCheck.isUnspecified() && (Sites.find(enclosingCheck) != Sites.end())) {
524  Site* tempSite = Sites.find(enclosingCheck)->second;
525  for(EnclosingSet::iterator itSet = tempSite->enclosingSet.begin(); itSet != tempSite->enclosingSet.end(); ++itSet) {
526  if(tempSite->oldEnclosingSet.find(*itSet) == tempSite->oldEnclosingSet.end()
527  && Sites.find(*itSet) != Sites.end()) {
528  Sites.find(*itSet)->second->type |= NEW;
529  }
530  }
531  tempSite->enclosingSet.swap(tempSite->oldEnclosingSet);
532  }
533  // reset inner- and outeredge indicator
534  itTemp->second->innerEdge[0] = false;
535  itTemp->second->innerEdge[1] = false;
536  itTemp->second->innerEdge[2] = false;
537  itTemp->second->outerEdge = false;
538  }
539  // clean up
540  edgelist.reset();
541  heap.PQreset();
542  geom.reset();
543 }
544 
546 {
548 }
549 
551 {
552  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end();) {
553  // if current site is no neighbor remove it else go on to next site
554  if(itSites->second->type == UNDEF) {
555  // Debug output
556  if(debugOutput) EV << "[NeighborsList::removeNeighbors()]\n"
557  << " Site at [" << itSites->second->coord.x << ", " << itSites->second->coord.y
558  << "] has been removed from list."
559  << endl;
560  Positions.erase(itSites->second->coord);
561  delete itSites->second;
562  Sites.erase(itSites++);
563  }
564  else ++itSites;
565  }
566 }
567 
569 {
570  if(state == READY) {
571  // debug output
572  if(debugOutput) {
573  EV << "[Vast::receiveChangeNotification() @ " << thisSite.addr.getIp()
574  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
575  << " Node " << thisSite.addr.getIp() << " is leaving the overlay."
576  << endl;
577  }
578 
579  CompReadyMessage* readyMsg = new CompReadyMessage("OVERLAY_FINISHED");
580  readyMsg->setReady(false);
581  readyMsg->setComp(getThisCompType());
582  sendToApp(readyMsg);
583  }
584 }
585 
587 {
588  if(state == READY) {
589  // generate node leave messages
590  VastListMessage *vastListMsg = new VastListMessage("NODE_LEAVE");
591  vastListMsg->setCommand(NODE_LEAVE);
592  // fill neighbors list
593  vastListMsg->setNeighborNodeArraySize(Sites.size());
594  vastListMsg->setNeighborPosArraySize(Sites.size());
595  int i = 0;
596  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
597  if(itSites->second->type & ENCLOSING) {
598  vastListMsg->setNeighborNode(i, itSites->second->addr);
599  vastListMsg->setNeighborPos(i, itSites->second->coord);
600  ++i;
601  }
602  }
603  vastListMsg->setNeighborNodeArraySize(i);
604  vastListMsg->setNeighborPosArraySize(i);
605 
606  vastListMsg->setBitLength(VASTLIST_L(vastListMsg));
607  if(vastListMsg->getNeighborNodeArraySize() > 0) {
608  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
609  VastListMessage *vastCopyMsg = new VastListMessage(*vastListMsg);
610  sendMessage(vastCopyMsg, itSites->second->addr);
611  }
612  }
613  delete vastListMsg;
614  changeState(INIT);
615  }
616 }
617 
619 {
620  GameAPIMessage *sgcMsg = new GameAPIMessage("MOVEMENT_REQUEST");
621  sgcMsg->setCommand(MOVEMENT_REQUEST);
622  sendToApp(sgcMsg);
623 }
624 
626 {
627  bool abnormalLeave = false;
628  bool boundaryLeave = false;
629  std::set<NodeHandle> removeSet;
630  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
631  if(itSites->second->tstamp < 0.0) { // node is dropped cause no pong has been received see below
632  abnormalLeave = true;
633  if(!(itSites->second->type & NEIGHBOR)) boundaryLeave = true;
634  itSites->second->type = UNDEF;
635  removeSet.insert( itSites->first );
636  }
637  else if(itSites->second->tstamp < simTime() - pingTimeout) { // node showed no activity for some time request pong and mark it to be dropped next time
638  VastMessage *vastMsg = new VastMessage("PING");
639  vastMsg->setCommand(PING);
640  vastMsg->setBitLength(VAST_L(vastMsg));
641  sendMessage(vastMsg, itSites->second->addr);
642  itSites->second->tstamp = -1.0;
643  }
644  }
645  if(abnormalLeave) {
646  synchronizeApp();
647  for( std::set<NodeHandle>::iterator it = removeSet.begin(); it != removeSet.end(); ++it) {
648  removeNode( *it );
649  }
650  // removeNeighbors();
651  if(boundaryLeave) {
652  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
653  if(itSites->second->type & BOUNDARY) {
654  VastMessage *vastMsg = new VastMessage("ENCLOSING_NEIGHBORS_REQUEST");
656  vastMsg->setBitLength(VAST_L(vastMsg));
657  sendMessage(vastMsg, itSites->second->addr);
658  }
659  }
660  }
661  //buildVoronoi();
662  //removeNeighbors(); should be superfluous
663  }
664 }
665 
667 {
668  RECORD_STATS(
671  }
673  ++secTimerCount;
674  );
675  bytesPerSecond = 0;
676 }
677 
679 {
680  double NeighborLevel;
681  int NeighborSum = 0;
682  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
683  if(itSites->second->neighborCount > 0) {
684  NeighborSum += itSites->second->neighborCount;
685  }
686  }
687  NeighborLevel = (double)(Sites.size() * Sites.size()) / (double)NeighborSum;
688 
689  if(NeighborLevel < criticalThreshold) {
690  VastListMessage *vastListMsg = new VastListMessage("BACKUP_NEIGHBORS");
691  vastListMsg->setCommand(BACKUP_NEIGHBORS);
692  // fill neighbors list
693  vastListMsg->setNeighborNodeArraySize(Sites.size());
694  vastListMsg->setNeighborPosArraySize(Sites.size());
695  int i = 0;
696  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
697  vastListMsg->setNeighborNode(i, itSites->second->addr);
698  vastListMsg->setNeighborPos(i, itSites->second->coord);
699  ++i;
700  }
701  vastListMsg->setBitLength(VASTLIST_L(vastListMsg));
702  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
703  VastListMessage *vastCopyMsg = new VastListMessage(*vastListMsg);
704  RECORD_STATS(
705  backupBytesSent += vastCopyMsg->getByteLength();
706  );
707  sendMessage(vastCopyMsg, itSites->second->addr);
708  }
709  delete vastListMsg;
710  }
711 }
712 
714 {
715  for(StockList::iterator itStock = Stock.begin(); itStock != Stock.end(); ++itStock) {
716  VastMoveMessage *vastMoveMsg = new VastMoveMessage("NODE_MOVE");
717  vastMoveMsg->setCommand(NODE_MOVE);
718  vastMoveMsg->setNewPos(thisSite.coord);
719  vastMoveMsg->setRequest_list(true);
720  vastMoveMsg->setBitLength(VASTMOVE_L(vastMoveMsg));
721  RECORD_STATS(
722  backupBytesSent += vastMoveMsg->getByteLength();
723  );
724  sendMessage(vastMoveMsg, *itStock);
725  }
726 }
727 
729 {
731  thisSite.coord = sgcMsg->getPosition();
732  // check if this is the only node in the overlay
733  if(joinNode.isUnspecified()) {
735  }
736  else {
737  VastMessage *vastMsg = new VastMessage("JOIN_REQUEST");
738  vastMsg->setCommand(JOIN_REQUEST);
739  vastMsg->setBitLength(VAST_L(vastMsg));
740  sendMessage(vastMsg, joinNode);
741  }
742 }
743 
745 {
746  Vector2D pos = sgcMsg->getPosition();
747  // test if new position is legal
748  if(Positions.find(pos) != Positions.end()) {
749  GameAPIMessage *gameMsg = new GameAPIMessage("MOVEMENT_REQUEST");
750  gameMsg->setCommand(MOVEMENT_REQUEST);
751  sendToApp(gameMsg);
752  return;
753  }
754  // set new position
755  thisSite.coord = pos;
756  // update voronoi
757  buildVoronoi();
758  synchronizeApp();
759  removeNeighbors();
760  // send position update to neighbors
761  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
762  VastMoveMessage *vastMoveMsg = new VastMoveMessage("NODE_MOVE");
763  vastMoveMsg->setCommand(NODE_MOVE);
764  vastMoveMsg->setNewPos(pos);
765  vastMoveMsg->setIs_boundary(itSites->second->type & BOUNDARY);
766  vastMoveMsg->setBitLength(VASTMOVE_L(vastMoveMsg));
767  sendMessage(vastMoveMsg, itSites->second->addr);
768  }
769 }
770 
772 {
773  // send event to neighbors
774  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
775  VastEventMessage *vastMsg = new VastEventMessage("EVENT");
776  vastMsg->setCommand(VAST_EVENT);
777  vastMsg->encapsulate((cPacket*)msg->dup());
778  // FIXME: Message length!
779  sendMessage(vastMsg, itSites->second->addr);
780  }
781 }
782 
784 {
785  Site *forwardSite = NULL;
786  // start with this node
787  double min_dist = thisSite.coord.distanceSqr(vastMsg->getPos());
788  forwardSite = &thisSite;
789  // iterate through all neighbors
790  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
791  // dont forward to nodes which are still joining
792  if(itSites->second->coord.distanceSqr(vastMsg->getPos()) < min_dist && itSites->second->neighborCount >= 0) {
793  min_dist = itSites->second->coord.distanceSqr(vastMsg->getPos());
794  forwardSite = itSites->second;
795  }
796  }
797  // do nothing and let node retry with new position if current position is illegal
798  if(min_dist == 0.0) {
799  delete vastMsg;
800  }
801  else {
802  // send an acknowledge or forward request if any of our neighbors is closer to joining node
803  if(forwardSite->type & THIS) {
804  VastListMessage *vastListMsg = new VastListMessage("JOIN_ACKNOWLEDGE");
805  vastListMsg->setCommand(JOIN_ACKNOWLEDGE);
806  // fill neighbors list
807  vastListMsg->setNeighborNodeArraySize(Sites.size());
808  vastListMsg->setNeighborPosArraySize(Sites.size());
809  int i = 0;
810  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
811  vastListMsg->setNeighborNode(i, itSites->second->addr);
812  vastListMsg->setNeighborPos(i, itSites->second->coord);
813  ++i;
814  }
815 
816  vastListMsg->setBitLength(VASTLIST_L(vastListMsg));
817  sendMessage(vastListMsg, vastMsg->getSourceNode());
818 
819  // add node to list to propagte its position early
820  // nieghborCount is set to -1 to indicate node is still joining
821  addNode(vastMsg->getPos(), vastMsg->getSourceNode(), -1);
822  // update voronoi with new neighbors
823  buildVoronoi();
824  synchronizeApp();
825  // removeNeighbors();
826  delete vastMsg;
827  }
828  else {
829  sendMessage(vastMsg, forwardSite->addr);
830  }
831  }
832 }
833 
835 {
836  // add acceptor node
838  addNode(vastListMsg->getPos(), vastListMsg->getSourceNode(), vastListMsg->getNeighborCount());
839  // add new neighbors
840  for(unsigned int i=0; i<vastListMsg->getNeighborNodeArraySize(); i++) {
841  addNode(vastListMsg->getNeighborPos(i), vastListMsg->getNeighborNode(i));
842  }
843  // update voronoi with new neighbors
844  buildVoronoi();
845  synchronizeApp();
846  // removeNeighbors();
847  // contact new neighbors
848  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
849  VastMoveMessage *vastMoveMsg = new VastMoveMessage("NODE_MOVE");
850  vastMoveMsg->setCommand(NODE_MOVE);
851  vastMoveMsg->setNewPos(thisSite.coord);
852  vastMoveMsg->setIs_boundary(itSites->second->type & BOUNDARY);
853  vastMoveMsg->setRequest_list(true);
854  vastMoveMsg->setBitLength(VASTMOVE_L(vastMoveMsg));
855  sendMessage(vastMoveMsg, itSites->second->addr);
856  }
857 }
858 
860 {
861  RECORD_STATS(
863  "Vast: MoveDelay",
864  SIMTIME_DBL(simTime()) - SIMTIME_DBL(vastMoveMsg->getCreationTime())
865  );
866  );
867 
868  Vector2D old_p, new_p;
869  old_p = vastMoveMsg->getPos();
870  new_p = vastMoveMsg->getNewPos();
871  addNode(new_p, vastMoveMsg->getSourceNode(), vastMoveMsg->getNeighborCount());
872  // update voronoi with new neighbor detection or without
873  if(vastMoveMsg->getIs_boundary() || vastMoveMsg->getRequest_list()) {
874  buildVoronoi(old_p, new_p, vastMoveMsg->getSourceNode()); // enhanced enclosing check
875  synchronizeApp(vastMoveMsg);
876  // removeNeighbors();
877  // send new neighbors
878  VastListMessage *vastListMsg = new VastListMessage("NEW_NEIGHBORS");
879  vastListMsg->setCommand(NEW_NEIGHBORS);
880 
881  vastListMsg->setNeighborNodeArraySize(Sites.size());
882  vastListMsg->setNeighborPosArraySize(Sites.size());
883 
884  int i = 0;
885  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
886  if(itSites->second->type & NEW || vastMoveMsg->getRequest_list()) {
887  vastListMsg->setNeighborNode(i, itSites->second->addr);
888  vastListMsg->setNeighborPos(i, itSites->second->coord);
889  ++i;
890  }
891  }
892  vastListMsg->setNeighborNodeArraySize(i);
893  vastListMsg->setNeighborPosArraySize(i);
894  vastListMsg->setRequestEnclosingNeighbors(true);
895 
896  vastListMsg->setBitLength(VASTLIST_L(vastListMsg));
897  if(vastListMsg->getNeighborNodeArraySize() > 0) {
898  RECORD_STATS(
899  if( vastMoveMsg->getRequest_list() ) backupBytesSent += vastListMsg->getByteLength();
900  );
901  sendMessage(vastListMsg, vastMoveMsg->getSourceNode());
902  }
903  else {
904  delete vastListMsg;
905  }
906  }
907  else {
908  // buildVoronoi();
909  synchronizeApp(vastMoveMsg);
910  // removeNeighbors();
911  }
912 }
913 
915 {
916  // add new neighbors
917  for(unsigned int i=0; i<vastListMsg->getNeighborNodeArraySize(); i++) {
918  addNode(vastListMsg->getNeighborPos(i), vastListMsg->getNeighborNode(i));
919 
920  if(vastListMsg->getRequestEnclosingNeighbors()) {
921  VastMessage *vastMsg = new VastMessage("ENCLOSING_NEIGHBORS_REQUEST");
923  vastMsg->setBitLength(VAST_L(vastMsg));
924  sendMessage(vastMsg, vastListMsg->getNeighborNode(i));
925  }
926  }
927  // update voronoi with new neighbors
928 // buildVoronoi();
929 // synchronizeApp();
930  // removeNeighbors();
931 }
932 
934 {
935  removeNode(vastListMsg->getSourceNode());
936  // add possible new neighbors
937  for(unsigned int i=0; i<vastListMsg->getNeighborNodeArraySize(); i++) {
938  addNode(vastListMsg->getNeighborPos(i), vastListMsg->getNeighborNode(i));
939  }
940  // update voronoi with new neighbors
941  // buildVoronoi();
942  // synchronizeApp();
943  // removeNeighbors();
944 }
945 
947 {
948  // send new neighbors
949  VastListMessage *vastListMsg = new VastListMessage("NEW_NEIGHBORS");
950  vastListMsg->setCommand(NEW_NEIGHBORS);
951 
952  vastListMsg->setNeighborNodeArraySize(Sites.size());
953  vastListMsg->setNeighborPosArraySize(Sites.size());
954 
955  int i = 0;
956  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
957  if((itSites->second->type & ENCLOSING) && itSites->second->addr != vastMsg->getSourceNode()) {
958  vastListMsg->setNeighborNode(i, itSites->second->addr);
959  vastListMsg->setNeighborPos(i, itSites->second->coord);
960  ++i;
961  }
962  }
963  vastListMsg->setNeighborNodeArraySize(i);
964  vastListMsg->setNeighborPosArraySize(i);
965 
966  vastListMsg->setBitLength(VASTLIST_L(vastListMsg));
967  if(vastListMsg->getNeighborNodeArraySize() > 0) {
968  sendMessage(vastListMsg, vastMsg->getSourceNode());
969  }
970  else {
971  delete vastListMsg;
972  }
973 }
974 
976 {
977  // add new neighbors to stock list
978  for(unsigned int i=0; i<vastListMsg->getNeighborNodeArraySize(); i++) {
979  if(Sites.find(vastListMsg->getNeighborNode(i)) == Sites.end()) {
980  addNodeToStock(vastListMsg->getNeighborNode(i));
981  }
982  }
983 }
984 
986 {
987  VastMessage *vastPongMsg = new VastMessage("PONG");
988  vastPongMsg->setCommand(PONG);
989  vastPongMsg->setBitLength(VAST_L(vastPongMsg));
990  sendMessage(vastPongMsg, vastMsg->getSourceNode());
991 }
992 
994 {
995  // replace entry cause it was probably outdated
996  addNode(vastMsg->getPos(), vastMsg->getSourceNode(), vastMsg->getNeighborCount());
997  // update voronoi
998  //buildVoronoi();
999  //synchronizeApp();
1000  // removeNeighbors();
1001 }
1002 
1004 {
1005  // discard outdated entry
1006  removeNode(vastMsg->getDiscardNode());
1007  // update voronoi
1008  //buildVoronoi();
1009  //synchronizeApp();
1010  // removeNeighbors();
1011 }
1012 
1014 {
1015  NodeHandle discardNode;
1016  discardNode.setIp(thisSite.addr.getIp());
1017  discardNode.setKey(vastMsg->getDestKey());
1018  // send message
1019  VastDiscardMessage *vastDiscardMsg = new VastDiscardMessage("DISCARD_NODE");
1020  vastDiscardMsg->setCommand(DISCARD_NODE);
1021  vastDiscardMsg->setDiscardNode(discardNode);
1022  // debug output
1023  if(debugOutput) EV << "[Vast::sendDiscardNode() @ " << thisSite.addr.getIp()
1024  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
1025  << " Node " << thisSite.addr.getIp() << " is leaving the overlay."
1026  << endl;
1027  vastDiscardMsg->setBitLength(VASTDISCARD_L(vastDiscardMsg));
1028  sendMessage(vastDiscardMsg, vastMsg->getSourceNode());
1029 }
1030 
1032 {
1033  GameAPIListMessage *sgcMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
1034  sgcMsg->setCommand(NEIGHBOR_UPDATE);
1035 
1036  sgcMsg->setRemoveNeighborArraySize(Sites.size());
1037  sgcMsg->setAddNeighborArraySize(Sites.size() + 1);
1038  sgcMsg->setNeighborPositionArraySize(Sites.size() + 1);
1039 
1040  int remSize, addSize;
1041  remSize = addSize = 0;
1042  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
1043  if(itSites->second->type == UNDEF) {
1044  sgcMsg->setRemoveNeighbor(remSize, itSites->second->addr);
1045  ++remSize;
1046  }
1047  else if(!itSites->second->isAdded) {
1048  sgcMsg->setAddNeighbor(addSize, itSites->second->addr);
1049  sgcMsg->setNeighborPosition(addSize, itSites->second->coord);
1050  itSites->second->isAdded = true;
1051  ++addSize;
1052  }
1053  }
1054 
1055  if(vastMoveMsg &&
1056  Sites.find(vastMoveMsg->getSourceNode()) != Sites.end() &&
1057  Sites.find(vastMoveMsg->getSourceNode())->second->isAdded) {
1058  sgcMsg->setAddNeighbor(addSize, vastMoveMsg->getSourceNode());
1059  sgcMsg->setNeighborPosition(addSize, vastMoveMsg->getNewPos());
1060  ++addSize;
1061  }
1062 
1063  sgcMsg->setRemoveNeighborArraySize(remSize);
1064  sgcMsg->setAddNeighborArraySize(addSize);
1065  sgcMsg->setNeighborPositionArraySize(addSize);
1066 
1067  if(sgcMsg->getAddNeighborArraySize() || sgcMsg->getRemoveNeighborArraySize()) {
1068  sendToApp(sgcMsg);
1069  }
1070  else {
1071  delete sgcMsg;
1072  }
1073 }
1074 
1075 void Vast::sendToApp(cMessage *msg)
1076 {
1077  // debug output
1078  if(debugOutput) EV << "[Vast::sendToApp() @ " << thisSite.addr.getIp()
1079  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
1080  << " Node " << thisSite.addr.getIp() << " sending " << msg->getName() << " to application."
1081  << endl;
1082  send(msg, "appOut");
1083 }
1084 
1085 void Vast::sendMessage(VastMessage *vastMsg, NodeHandle destAddr)
1086 {
1087  // collect statistics
1088  RECORD_STATS(
1089  switch(vastMsg->getCommand()) {
1090  case JOIN_REQUEST: {
1091  joinRequestBytesSent += vastMsg->getByteLength();
1092  } break;
1093  case JOIN_ACKNOWLEDGE: {
1094  joinAcknowledgeBytesSent += vastMsg->getByteLength();
1095  } break;
1096  case NODE_MOVE: {
1097  nodeMoveBytesSent += vastMsg->getByteLength();
1098  } break;
1099  case NEW_NEIGHBORS: {
1100  newNeighborsBytesSent += vastMsg->getByteLength();
1101  } break;
1102  case NODE_LEAVE: {
1103  nodeLeaveBytesSent += vastMsg->getByteLength();
1104  } break;
1106  enclosingNeighborsRequestBytesSent += vastMsg->getByteLength();
1107  } break;
1108  case PING: {
1109  pingBytesSent += vastMsg->getByteLength();
1110  } break;
1111  case PONG: {
1112  pongBytesSent += vastMsg->getByteLength();
1113  } break;
1114  case DISCARD_NODE: {
1115  discardNodeBytesSent += vastMsg->getByteLength();
1116  } break;
1117  }
1118  bytesPerSecond += vastMsg->getByteLength();
1119  );
1120 
1121  // debug output
1122  if(debugOutput) EV << "[Vast::sendMessage() @ " << thisSite.addr.getIp()
1123  << " (" << thisSite.addr.getKey().toString(16) << ")]\n"
1124  << " Node " << thisSite.addr.getIp() << " sending " << vastMsg->getName() << " to " << destAddr.getIp() << "."
1125  << endl;
1126  // set vastbase message stuff
1127  vastMsg->setDestKey(destAddr.getKey());
1128  // fill in sender information only if we are not forwarding a message from another node
1129  // e.g. a joining node
1130  if(vastMsg->getSourceNode().isUnspecified()) {
1131  vastMsg->setSourceNode(thisSite.addr);
1132  vastMsg->setPos(thisSite.coord);
1133  vastMsg->setNeighborCount(Sites.size());
1134  }
1135 
1136  sendMessageToUDP(destAddr, vastMsg);
1137 }
1138 
1140 {
1141  if(ev.isGUI()) {
1142  if(state == READY) {
1143  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "green");
1144  getDisplayString().setTagArg("i", 1, "green");
1145  }
1146  else if(state == JOIN) {
1147  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "yellow");
1148  getDisplayString().setTagArg("i", 1, "yellow");
1149  }
1150  else {
1151  getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "red");
1152  getDisplayString().setTagArg("i", 1, "red");
1153  }
1154  }
1155 }
1156 
1158 {
1160 
1161 // We use our own time count to avoid rounding errors
1162 // simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
1163 // if(time == 0) return;
1164  if(secTimerCount == 0) return;
1165 
1166  // collect statistics
1167  globalStatistics->addStdDev("Vast: JOIN_REQUEST bytes sent/s", joinRequestBytesSent/(double) secTimerCount);
1168  globalStatistics->addStdDev("Vast: JOIN_ACKNOWLEDGE bytes sent/s", joinAcknowledgeBytesSent/(double) secTimerCount);
1169  globalStatistics->addStdDev("Vast: NODE_MOVE bytes sent/s", nodeMoveBytesSent/(double) secTimerCount);
1170  globalStatistics->addStdDev("Vast: NEW_NEIGHBORS bytes sent/s", newNeighborsBytesSent/(double) secTimerCount);
1171  globalStatistics->addStdDev("Vast: NODE_LEAVE bytes sent/s", nodeLeaveBytesSent/(double) secTimerCount);
1172  globalStatistics->addStdDev("Vast: ENCLOSING_NEIGHBORS_REQUEST bytes sent/s", enclosingNeighborsRequestBytesSent/(double) secTimerCount);
1173  globalStatistics->addStdDev("Vast: PING bytes sent/s", pingBytesSent/(double) secTimerCount);
1174  globalStatistics->addStdDev("Vast: PONG bytes sent/s", pongBytesSent/(double) secTimerCount);
1175  globalStatistics->addStdDev("Vast: DISCARD_NODE bytes sent/s", discardNodeBytesSent/(double) secTimerCount);
1176  globalStatistics->addStdDev("Vast: BACKUP bytes sent/s", backupBytesSent/(double) secTimerCount);
1177  globalStatistics->addStdDev("Vast: max bytes/second sent", maxBytesPerSecondSent);
1178  globalStatistics->addStdDev("Vast: average bytes/second sent", averageBytesPerSecondSent / (double) secTimerCount);
1179 }
1180 
1182 {
1183  Enter_Method_Silent();
1184  return AOI_size;
1185 }
1186 
1188 {
1189  Enter_Method_Silent();
1190  return thisSite.coord;
1191 }
1192 
1194 {
1195  Enter_Method_Silent();
1196  return thisSite.addr;
1197 }
1198 
1200 {
1201  Enter_Method_Silent();
1202  return areaDimension;
1203 }
1204 
1206 {
1207  if(Sites.size()) {
1208  for(SiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
1209  delete itSites->second;
1210  }
1211  Sites.clear();
1212  Positions.clear();
1213  }
1214  // destroy self timer messages
1215  cancelAndDelete(join_timer);
1216  cancelAndDelete(ping_timer);
1217  cancelAndDelete(sec_timer);
1218  cancelAndDelete(discovery_timer);
1219  cancelAndDelete(checkcritical_timer);
1220 }