00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00025 #include <Quon.h>
00026 #include <BootstrapList.h>
00027 #include <limits>
00028
00029 Define_Module(Quon);
00030
00031 void Quon::initializeOverlay(int stage)
00032 {
00033
00034
00035 if(stage != MIN_STAGE_OVERLAY) {
00036 return;
00037 }
00038
00039
00040 minAOI = (double)par("minAOIWidth") * (double)par("AOIBufferFactor");
00041 maxAOI = (double)par("AOIWidth") * (double)par("AOIBufferFactor");
00042 AOIWidth = maxAOI;
00043 connectionLimit = par("connectionLimit");
00044 areaDimension = par("areaDimension");
00045 joinTimeout = par("joinTimeout");
00046 deleteTimeout = par("deleteTimeout");
00047 aliveTimeout = (double)par("aliveTimeout") / 2.0;
00048 backupIntervall = par("contactBackupIntervall");
00049 AOIAdaptionIntervall = par("AOIAdaptionIntervall");
00050 linearAdaption = par("AOIAdaptLinear");
00051 adaptionSensitivity = par("AOIAdaptionSensitivity");
00052 gossipSensitivity = par("AOIGossipSensitivity");
00053 useSquareMetric = par("useSquareMetric");
00054
00055
00056 useDynamicAOI = (connectionLimit > 0 && minAOI < maxAOI && AOIAdaptionIntervall > 0.0) ? true : false;
00057
00058
00059 thisNode.setKey(OverlayKey::random());
00060 thisSite = new QuonSite();
00061 thisSite->address = thisNode;
00062 thisSite->type = QTHIS;
00063
00064
00065 join_timer = new cMessage("join_timer");
00066 sec_timer = new cMessage("sec_timer");
00067 alive_timer = new cMessage("alive_timer");
00068 backup_timer = new cMessage("backup_timer");
00069 adaption_timer = new cMessage("adaption_timer");
00070
00071
00072 joinRequestBytesSend = 0.0;
00073 joinAcknowledgeBytesSend = 0.0;
00074 nodeMoveBytesSend = 0.0;
00075 newNeighborsBytesSend = 0.0;
00076 nodeLeaveBytesSend = 0.0;
00077 maxBytesPerSecondSend = 0.0;
00078 averageBytesPerSecondSend = 0.0;
00079 bytesPerSecond = 0.0;
00080 softConnections = 0;
00081 softNeighborCount = 0;
00082 bindingNeighborCount = 0;
00083 directNeighborCount = 0;
00084 secTimerCount = 0;
00085
00086 avgAOI= 0 ;
00087
00088
00089 WATCH(thisSite->address);
00090 WATCH(thisSite->position);
00091 WATCH(AOIWidth);
00092
00093
00094
00095 WATCH(joinRequestBytesSend);
00096 WATCH(joinAcknowledgeBytesSend);
00097 WATCH(nodeMoveBytesSend);
00098 WATCH(newNeighborsBytesSend);
00099 WATCH(nodeLeaveBytesSend);
00100 WATCH(maxBytesPerSecondSend);
00101 WATCH(bytesPerSecond);
00102 WATCH(softConnections);
00103 WATCH(softNeighborCount);
00104 WATCH(bindingNeighborCount);
00105 WATCH(directNeighborCount);
00106
00107
00108
00109 changeState(QUNINITIALIZED);
00110 changeState(QJOINING);
00111 }
00112
00113 void Quon::changeState(QState qstate)
00114 {
00115 this->qstate = qstate;
00116 switch(qstate) {
00117 case QUNINITIALIZED:
00118 globalNodeList->removePeer(thisSite->address);
00119 cancelEvent(join_timer);
00120 cancelEvent(sec_timer);
00121 cancelEvent(alive_timer);
00122 cancelEvent(backup_timer);
00123 cancelEvent(adaption_timer);
00124 break;
00125 case QJOINING:
00126 scheduleAt(simTime(), join_timer);
00127 scheduleAt(simTime() + 1.0, sec_timer);
00128 break;
00129 case QREADY:
00130 cancelEvent(join_timer);
00131 globalNodeList->registerPeer(thisSite->address);
00132
00133
00134 CompReadyMessage* readyMsg = new CompReadyMessage("OVERLAY_READY");
00135 readyMsg->setReady(true);
00136 readyMsg->setComp(getThisCompType());
00137
00138 sendToApp(readyMsg);
00139
00140
00141 AOIWidth = maxAOI;
00142 GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00143 gameMsg->setCommand(RESIZE_AOI);
00144 gameMsg->setAOIsize(AOIWidth);
00145 sendToApp(gameMsg);
00146 if(aliveTimeout > 0.0) {
00147 scheduleAt(simTime() + aliveTimeout, alive_timer);
00148 }
00149 if(backupIntervall > 0.0) {
00150 scheduleAt(simTime() + backupIntervall, backup_timer);
00151 }
00152 if(useDynamicAOI) {
00153 scheduleAt(simTime() + AOIAdaptionIntervall, adaption_timer);
00154 }
00155 break;
00156 }
00157 setBootstrapedIcon();
00158
00159 if(debugOutput) {
00160 EV << "[Quon::changeState() @ " << thisNode.getAddress()
00161 << " (" << thisNode.getKey().toString(16) << ")]\n"
00162 << " Node " << thisSite->address.getAddress() << " entered ";
00163 switch(qstate) {
00164 case QUNINITIALIZED:
00165 EV << "UNINITIALIZED";
00166 break;
00167 case QJOINING:
00168 EV << "JOINING";
00169 break;
00170 case QREADY:
00171 EV << "READY";
00172 break;
00173 }
00174 EV << " state." << endl;
00175 }
00176 }
00177
00178 void Quon::handleTimerEvent(cMessage* msg)
00179 {
00180 if(msg->isName("join_timer")) {
00181
00182 cancelEvent(join_timer);
00183 if(qstate != QREADY) {
00184 scheduleAt(simTime() + joinTimeout, msg);
00185
00186 processJoinTimer();
00187 }
00188 }
00189 else if(msg->isName("sec_timer")) {
00190
00191 cancelEvent(sec_timer);
00192 scheduleAt(simTime() + 1, msg);
00193
00194 processSecTimer();
00195 }
00196 else if(msg->isName("delete_timer")) {
00197
00198 processDeleteTimer(msg);
00199 }
00200 else if(msg->isName("alive_timer")) {
00201
00202 cancelEvent(alive_timer);
00203 scheduleAt(simTime() + aliveTimeout, msg);
00204
00205 processAliveTimer();
00206 }
00207 else if(msg->isName("backup_timer")) {
00208
00209 cancelEvent(backup_timer);
00210 scheduleAt(simTime() + backupIntervall, msg);
00211
00212 processBackupTimer();
00213 }
00214 else if(msg->isName("adaption_timer")) {
00215
00216 cancelEvent(adaption_timer);
00217 scheduleAt(simTime() + AOIAdaptionIntervall, msg);
00218
00219 #if 0
00220
00221 if((Sites.size() > connectionLimit && AOIWidth > minAOI) || (Sites.size() < connectionLimit && AOIWidth < maxAOI)) {
00222 AOIWidth -= (maxAOI - minAOI) * (Sites.size() - connectionLimit) / 200.0;
00223 if(AOIWidth > maxAOI) {
00224 AOIWidth = maxAOI;
00225 }
00226 else if(AOIWidth < minAOI) {
00227 AOIWidth = minAOI;
00228 }
00229 GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00230 gameMsg->setCommand(RESIZE_AOI);
00231 gameMsg->setAOIsize(AOIWidth);
00232 sendToApp(gameMsg);
00233 }
00234
00235 #endif
00236 double oldAOI = AOIWidth;
00237 if( linearAdaption ) {
00238 AOIWidth -= (maxAOI - minAOI) * ((double) Sites.size() - (double) connectionLimit) * adaptionSensitivity / (double) connectionLimit;
00239 } else if( Sites.size() > 0 ){
00240 AOIWidth *= (1-adaptionSensitivity) + (double) connectionLimit * adaptionSensitivity / (double) Sites.size();
00241 }
00242 if( gossipSensitivity > 0 && Sites.size() > 0 ) {
00243 double avgNeighborAOI = 0;
00244 for( QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites ){
00245 avgNeighborAOI += itSites->second->AOIwidth;
00246 }
00247 avgNeighborAOI /= Sites.size();
00248 AOIWidth = AOIWidth*(1-gossipSensitivity) + avgNeighborAOI*gossipSensitivity;
00249 }
00250 if(AOIWidth > maxAOI) {
00251 AOIWidth = maxAOI;
00252 }
00253 else if(AOIWidth < minAOI) {
00254 AOIWidth = minAOI;
00255 }
00256
00257 if( oldAOI != AOIWidth ){
00258 GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00259 gameMsg->setCommand(RESIZE_AOI);
00260 gameMsg->setAOIsize(AOIWidth);
00261 sendToApp(gameMsg);
00262 }
00263 }
00264 }
00265
00266 void Quon::handleAppMessage(cMessage* msg)
00267 {
00268 GameAPIMessage* gameAPIMsg = dynamic_cast<GameAPIMessage*>(msg);
00269 if(gameAPIMsg != NULL) {
00270
00271 if(debugOutput) {
00272 EV << "[Quon::handleAppMessage() @ " << thisNode.getAddress()
00273 << " (" << thisNode.getKey().toString(16) << ")]\n"
00274 << " Node " << thisSite->address.getAddress() << " received " << gameAPIMsg->getName() << " from application."
00275 << endl;
00276 }
00277 switch(gameAPIMsg->getCommand()) {
00278 case MOVEMENT_INDICATION: {
00279 GameAPIPositionMessage* gameAPIPositionMsg = dynamic_cast<GameAPIPositionMessage*>(msg);
00280 if(qstate == QJOINING) {
00281 handleJoin(gameAPIPositionMsg);
00282 }
00283 else if(qstate == QREADY) {
00284 handleMove(gameAPIPositionMsg);
00285 }
00286 } break;
00287 case GAMEEVENT_CHAT:
00288 case GAMEEVENT_SNOW:
00289 case GAMEEVENT_FROZEN: {
00290 handleEvent(gameAPIMsg);
00291 } break;
00292 }
00293 }
00294 delete msg;
00295 }
00296
00297 void Quon::handleUDPMessage(BaseOverlayMessage* msg)
00298 {
00299 if(qstate == QUNINITIALIZED) {
00300 delete msg;
00301 return;
00302 }
00303 QuonMessage* quonMsg = dynamic_cast<QuonMessage*>(msg);
00304 if(quonMsg != NULL) {
00305
00306 if(debugOutput) {
00307 EV << "[Quon::handleUDPMessage() @ " << thisNode.getAddress()
00308 << " (" << thisNode.getKey().toString(16) << ")]\n"
00309 << " Node " << thisSite->address.getAddress() << " received " << quonMsg->getName() << " from " << quonMsg->getSender().getAddress() << "."
00310 << endl;
00311 }
00312 if(qstate == QREADY) {
00313 switch(quonMsg->getCommand()) {
00314 case JOIN_REQUEST: {
00315 handleJoinRequest(quonMsg);
00316 } break;
00317 case NODE_MOVE: {
00318 QuonMoveMessage* quonMoveMsg = dynamic_cast<QuonMoveMessage*>(msg);
00319 handleNodeMove(quonMoveMsg);
00320 delete msg;
00321 } break;
00322 case NEW_NEIGHBORS: {
00323 QuonListMessage* quonListMsg = dynamic_cast<QuonListMessage*>(msg);
00324 handleNewNeighbors(quonListMsg);
00325 delete msg;
00326 } break;
00327 case NODE_LEAVE: {
00328 QuonListMessage* quonListMsg = dynamic_cast<QuonListMessage*>(msg);
00329 handleNodeLeave(quonListMsg);
00330 delete msg;
00331 } break;
00332 case QUON_EVENT: {
00333 sendToApp(quonMsg->decapsulate());
00334 delete quonMsg;
00335 } break;
00336 }
00337 }
00338 else if(qstate == QJOINING && quonMsg->getCommand() == JOIN_ACKNOWLEDGE) {
00339 QuonListMessage* quonListMsg = dynamic_cast<QuonListMessage*>(msg);
00340 handleJoinAcknowledge(quonListMsg);
00341 delete msg;
00342 }
00343 else {
00344 delete msg;
00345 }
00346 }
00347 else {
00348 delete msg;
00349 }
00350 }
00351
00352 bool Quon::addSite(Vector2D p, NodeHandle node, double AOI, bool isSoft, QUpdateType update)
00353 {
00354 QuonSiteMap::iterator itSites = Sites.find(node.getKey());
00355 if(node.getKey() != thisSite->address.getKey() && deletedSites.find(node.getKey()) == deletedSites.end()) {
00356 if(itSites == Sites.end()) {
00357 if(debugOutput) {
00358 EV << "[Quon::addSite() @ " << thisNode.getAddress()
00359 << " (" << thisNode.getKey().toString(16) << ")]\n"
00360 << " Site " << node.getAddress() << " at " << p << " has been added to the list."
00361 << endl;
00362 }
00363 QuonSite* temp = new QuonSite();
00364 temp->position = p;
00365 temp->address = node;
00366 if(update == QDIRECT) {
00367 temp->dirty = true;
00368 }
00369 temp->alive = true;
00370 temp->type = QUNDEFINED;
00371 temp->softNeighbor = isSoft;
00372 temp->AOIwidth = AOI;
00373
00374 Sites.insert(std::make_pair(temp->address.getKey(), temp));
00375 }
00376 else if(update == QDIRECT || !itSites->second->alive) {
00377 if(debugOutput) {
00378 EV << "[Quon::addSite() @ " << thisNode.getAddress()
00379 << " (" << thisNode.getKey().toString(16) << ")]\n"
00380 << " Site " << node.getAddress() << " at " << p << " has been updated in the list."
00381 << endl;
00382 }
00383 itSites->second->position = p;
00384 itSites->second->dirty = true;
00385 itSites->second->alive = true;
00386 itSites->second->softNeighbor = isSoft;
00387 itSites->second->type = QUNDEFINED;
00388 itSites->second->AOIwidth = AOI;
00389 }
00390 return true;
00391 }
00392 return false;
00393 }
00394
00395 void Quon::updateThisSite(Vector2D p)
00396 {
00397 if(debugOutput) {
00398 EV << "[Quon::updateThisSite() @ " << thisNode.getAddress()
00399 << " (" << thisNode.getKey().toString(16) << ")]\n"
00400 << " This Site position has been updated to " << p << "."
00401 << endl;
00402 }
00403 thisSite->position = p;
00404 }
00405
00406 void Quon::classifySites()
00407 {
00408 if(Sites.size() > 0) {
00409 QuonAOI AOI(thisSite->position, AOIWidth, useSquareMetric);
00410 QuonSite* bindings[4] = {0, 0, 0, 0};
00411 QuonSite* backupCandidates[4] = {0, 0, 0, 0};
00412 double bindingDistance[4] = {std::numeric_limits<double>::infinity(),
00413 std::numeric_limits<double>::infinity(),
00414 std::numeric_limits<double>::infinity(),
00415 std::numeric_limits<double>::infinity()};
00416 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00417 QuonAOI NeighborAOI(itSites->second->position, itSites->second->AOIwidth, useSquareMetric);
00418 if(AOI.collide(itSites->second->position) || NeighborAOI.collide(thisSite->position)) {
00419 if(itSites->second->type != QNEIGHBOR) {
00420 itSites->second->type = QNEIGHBOR;
00421 itSites->second->dirty = true;
00422 }
00423 }
00424 else if(itSites->second->type != QUNDEFINED) {
00425 itSites->second->type = QUNDEFINED;
00426 itSites->second->dirty = true;
00427 }
00428 int quad = thisSite->position.getQuadrant( itSites->second->position );
00429 int dist;
00430 if( useSquareMetric ) {
00431 dist = thisSite->position.xyMaxDistance(itSites->second->position);
00432 } else {
00433 dist = thisSite->position.distanceSqr(itSites->second->position);
00434 }
00435
00436 if( dist < bindingDistance[quad] ){
00437 backupCandidates[quad] = bindings[quad];
00438 bindings[quad] = itSites->second;
00439 bindingDistance[quad] = dist;
00440 }
00441 }
00442 for( int i = 0; i < 4; ++i ){
00443 if( bindings[i] ){
00444 bindings[i]->type = QBINDING;
00445 bindings[i]->dirty = true;
00446
00447
00448 if( backupCandidates[i] ){
00449 bindingBackup[i] = backupCandidates[i]->address;
00450 }
00451 }
00452 }
00453 }
00454 else {
00455 ++rejoinCount;
00456
00457 changeState(QUNINITIALIZED);
00458 changeState(QJOINING);
00459 }
00460 }
00461
00462 bool Quon::deleteSite(NodeHandle node)
00463 {
00464 QuonSiteMap::iterator itSites = Sites.find(node.getKey());
00465 if(itSites != Sites.end()) {
00466 if(debugOutput) {
00467 EV << "[Quon::deleteSite() @ " << thisNode.getAddress()
00468 << " (" << thisNode.getKey().toString(16) << ")]\n"
00469 << " Site " << node.getAddress() << " at " << itSites->second->position << " has been removed from the list."
00470 << endl;
00471 }
00472 delete itSites->second;
00473 Sites.erase(itSites);
00474 return true;
00475 }
00476 return false;
00477 }
00478
00479 int Quon::purgeSites(QPurgeType purgeSoftSites)
00480 {
00481 int purged = 0;
00482 QuonSiteMap::iterator itSites = Sites.begin();
00483 while(itSites != Sites.end()) {
00484
00485 if(itSites->second->type == QUNDEFINED && ( purgeSoftSites == QPURGESOFT || !itSites->second->softNeighbor) ) {
00486 if(debugOutput) {
00487 EV << "[Quon::purgeSites() @ " << thisNode.getAddress()
00488 << " (" << thisNode.getKey().toString(16) << ")]\n"
00489 << " Site " << itSites->second->address.getAddress() << " at " << itSites->second->position << " has been removed from the list.\n"
00490 << " Status: " << ((itSites->second->type == QUNDEFINED) ? "QUNDEFINED" : "QSOFT")
00491 << endl;
00492 }
00493 delete itSites->second;
00494 Sites.erase(itSites++);
00495 ++purged;
00496 }
00497 else {
00498 ++itSites;
00499 }
00500 }
00501 return purged;
00502 }
00503
00504 void Quon::handleNodeGracefulLeaveNotification()
00505 {
00506 if(qstate == QREADY) {
00507 CompReadyMessage* readyMsg = new CompReadyMessage("OVERLAY_FINISHED");
00508 readyMsg->setReady(false);
00509 readyMsg->setComp(getThisCompType());
00510
00511 sendToApp(readyMsg);
00512 if(Sites.size() > 0) {
00513
00514 QuonListMessage* quonListMsg = new QuonListMessage("NODE_LEAVE");
00515 quonListMsg->setCommand(NODE_LEAVE);
00516 quonListMsg->setSender(thisSite->address);
00517 quonListMsg->setPosition(thisSite->position);
00518 quonListMsg->setAOIsize(AOIWidth);
00519
00520 quonListMsg->setNeighborHandleArraySize(Sites.size());
00521 quonListMsg->setNeighborPositionArraySize(Sites.size());
00522 int i = 0;
00523 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00524 quonListMsg->setNeighborHandle(i, itSites->second->address);
00525 quonListMsg->setNeighborPosition(i, itSites->second->position);
00526 ++i;
00527 }
00528 quonListMsg->setBitLength(QUONLIST_L(quonListMsg));
00529
00530 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00531 QuonListMessage* quonCopyMsg = new QuonListMessage(*quonListMsg);
00532 sendMessage(quonCopyMsg, itSites->second->address);
00533 }
00534 delete quonListMsg;
00535 }
00536 changeState(QUNINITIALIZED);
00537 }
00538 }
00539
00540 void Quon::processJoinTimer()
00541 {
00542 GameAPIMessage* gameMsg = new GameAPIMessage("MOVEMENT_REQUEST");
00543 gameMsg->setCommand(MOVEMENT_REQUEST);
00544 sendToApp(gameMsg);
00545 }
00546
00547 void Quon::processSecTimer()
00548 {
00549 RECORD_STATS(
00550 if(bytesPerSecond > maxBytesPerSecondSend) {
00551 maxBytesPerSecondSend = bytesPerSecond;
00552 }
00553 avgAOI += AOIWidth;
00554 averageBytesPerSecondSend += bytesPerSecond;
00555 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00556 switch(itSites->second->type) {
00557 case QNEIGHBOR:
00558 directNeighborCount++;
00559 break;
00560 case QBINDING:
00561 bindingNeighborCount++;
00562 break;
00563 case QUNDEFINED:
00564 if( itSites->second->softNeighbor ){
00565 softNeighborCount++;
00566 }
00567 break;
00568 case QTHIS:
00569 break;
00570 }
00571 }
00572 ++secTimerCount;
00573 );
00574 bytesPerSecond = 0.0;
00575 }
00576
00577 void Quon::processDeleteTimer(cMessage* msg)
00578 {
00579 QuonSelfMessage* quonMsg = dynamic_cast<QuonSelfMessage*>(msg);
00580 QDeleteMap::iterator itSite = deletedSites.find(quonMsg->getKey());
00581 if(itSite != deletedSites.end()) {
00582 deletedSites.erase(itSite);
00583 }
00584 cancelAndDelete(quonMsg);
00585 }
00586
00587 void Quon::processAliveTimer()
00588 {
00589 bool rebuild = false;
00590 QuonSiteMap::iterator itSites = Sites.begin();
00591 while(itSites != Sites.end()) {
00592 if(itSites->second->alive) {
00593 itSites->second->alive = false;
00594 ++itSites;
00595 }
00596 else {
00597 NodeHandle node = itSites->second->address;
00598 ++itSites;
00599 deleteSite(node);
00600
00601 deleteAppNeighbor(node);
00602 if(!rebuild) {
00603 rebuild = true;
00604 }
00605 }
00606 }
00607 if(rebuild) {
00608 classifySites();
00609
00610 synchronizeAppNeighbors();
00611 purgeSites();
00612 }
00613 }
00614
00615 void Quon::processBackupTimer()
00616 {
00617 QuonMoveMessage* quonMoveMsg = new QuonMoveMessage("NODE_MOVE");
00618 quonMoveMsg->setCommand(NODE_MOVE);
00619 quonMoveMsg->setSender(thisSite->address);
00620 quonMoveMsg->setPosition(thisSite->position);
00621 quonMoveMsg->setAOIsize(AOIWidth);
00622 quonMoveMsg->setNewPosition(thisSite->position);
00623 quonMoveMsg->setIsBinding(true);
00624 for(unsigned int i=0; i<4; i++) {
00625 if(!bindingBackup[i].isUnspecified()) {
00626 QuonMoveMessage* copyMsg = new QuonMoveMessage(*quonMoveMsg);
00627 copyMsg->setBitLength(QUONMOVE_L(copyMsg));
00628 sendMessage(copyMsg, bindingBackup[i]);
00629 }
00630 }
00631 delete quonMoveMsg;
00632 }
00633
00634 void Quon::handleJoin(GameAPIPositionMessage* gameMsg)
00635 {
00636 TransportAddress joinNode = bootstrapList->getBootstrapNode();
00637 thisSite->position = gameMsg->getPosition();
00638
00639 if(joinNode.isUnspecified()) {
00640 changeState(QREADY);
00641 }
00642 else {
00643 QuonMessage* quonMsg = new QuonMessage("JOIN_REQUEST");
00644 quonMsg->setCommand(JOIN_REQUEST);
00645 quonMsg->setSender(thisSite->address);
00646 quonMsg->setPosition(thisSite->position);
00647 quonMsg->setAOIsize(AOIWidth);
00648 quonMsg->setBitLength(QUON_L(quonMsg));
00649 sendMessage(quonMsg, joinNode);
00650 }
00651 }
00652
00653 void Quon::handleMove(GameAPIPositionMessage* gameMsg)
00654 {
00655 Vector2D position = gameMsg->getPosition();
00656
00657 QuonMoveMessage* quonMoveMsg = new QuonMoveMessage("NODE_MOVE");
00658 quonMoveMsg->setCommand(NODE_MOVE);
00659 quonMoveMsg->setSender(thisSite->address);
00660 quonMoveMsg->setPosition(thisSite->position);
00661 quonMoveMsg->setAOIsize(AOIWidth);
00662 quonMoveMsg->setNewPosition(position);
00663 quonMoveMsg->setBitLength(QUONMOVE_L(quonMoveMsg));
00664
00665 QuonMoveMessage* quonMoveBindingMsg = new QuonMoveMessage(*quonMoveMsg);
00666 quonMoveBindingMsg->setNeighborHandleArraySize(Sites.size());
00667 quonMoveBindingMsg->setNeighborPositionArraySize(Sites.size());
00668 int i = 0;
00669 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00670 if(itSites->second->type == QBINDING || itSites->second->softNeighbor ) {
00671 quonMoveBindingMsg->setNeighborHandle(i, itSites->second->address);
00672 quonMoveBindingMsg->setNeighborPosition(i, itSites->second->position);
00673 ++i;
00674 }
00675 }
00676 quonMoveBindingMsg->setNeighborHandleArraySize(i);
00677 quonMoveBindingMsg->setNeighborPositionArraySize(i);
00678 if(i > 0) {
00679
00680
00681
00682 quonMoveBindingMsg->setBitLength(QUONMOVE_L(quonMoveBindingMsg) - QUONENTRY_L);
00683 }
00684
00685 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00686 QuonMoveMessage* copyMsg;
00687 if(itSites->second->type == QBINDING || itSites->second->softNeighbor ) {
00688 copyMsg = new QuonMoveMessage(*quonMoveBindingMsg);
00689 if(itSites->second->type == QBINDING) {
00690 copyMsg->setIsBinding(true);
00691 }
00692 else {
00693 ++softConnections;
00694 }
00695 }
00696 else {
00697 copyMsg = new QuonMoveMessage(*quonMoveMsg);
00698 }
00699 sendMessage(copyMsg, itSites->second->address);
00700 }
00701 delete quonMoveMsg;
00702 delete quonMoveBindingMsg;
00703
00704
00705 updateThisSite(position);
00706 classifySites();
00707
00708 synchronizeAppNeighbors(QPURGESOFT);
00709 purgeSites(QPURGESOFT);
00710 }
00711
00712 void Quon::handleEvent(GameAPIMessage* msg)
00713 {
00714
00715 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00716 QuonEventMessage *quonMsg = new QuonEventMessage("EVENT");
00717 quonMsg->setCommand(QUON_EVENT);
00718 quonMsg->encapsulate((cPacket*)msg->dup());
00719
00720 sendMessage(quonMsg, itSites->second->address);
00721 }
00722 }
00723
00724 void Quon::handleJoinRequest(QuonMessage* quonMsg)
00725 {
00726 Vector2D joinPosition = quonMsg->getPosition();
00727
00728 double min_dist = thisSite->position.distanceSqr(joinPosition);
00729 QuonSite* forwardSite = thisSite;
00730
00731 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00732 if(itSites->second->position.distanceSqr(joinPosition) < min_dist) {
00733 min_dist = itSites->second->position.distanceSqr(joinPosition);
00734 forwardSite = itSites->second;
00735 }
00736 }
00737
00738
00739 if(min_dist == 0.0) {
00740 delete quonMsg;
00741 }
00742 else if(forwardSite->type == QTHIS) {
00743 QuonListMessage* quonListMsg = new QuonListMessage("JOIN_ACKNOWLEDGE");
00744 quonListMsg->setCommand(JOIN_ACKNOWLEDGE);
00745 quonListMsg->setSender(thisSite->address);
00746 quonListMsg->setPosition(thisSite->position);
00747 quonListMsg->setAOIsize(AOIWidth);
00748
00749 quonListMsg->setNeighborHandleArraySize(Sites.size());
00750 quonListMsg->setNeighborPositionArraySize(Sites.size());
00751 int i = 0;
00752 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00753 quonListMsg->setNeighborHandle(i, itSites->second->address);
00754 quonListMsg->setNeighborPosition(i, itSites->second->position);
00755 ++i;
00756 }
00757 quonListMsg->setNeighborHandleArraySize(i);
00758 quonListMsg->setNeighborPositionArraySize(i);
00759
00760 quonListMsg->setBitLength(QUONLIST_L(quonListMsg));
00761 sendMessage(quonListMsg, quonMsg->getSender());
00762 delete quonMsg;
00763 }
00764 else {
00765 sendMessage(quonMsg, forwardSite->address);
00766 }
00767 }
00768
00769 void Quon::handleJoinAcknowledge(QuonListMessage* quonListMsg)
00770 {
00771
00772 changeState(QREADY);
00773 addSite(quonListMsg->getPosition(), quonListMsg->getSender(), quonListMsg->getAOIsize(), false, QDIRECT);
00774
00775 for(unsigned int i=0; i<quonListMsg->getNeighborHandleArraySize(); i++) {
00776 addSite(quonListMsg->getNeighborPosition(i), quonListMsg->getNeighborHandle(i), quonListMsg->getAOIsize());
00777 }
00778 classifySites();
00779
00780 synchronizeAppNeighbors();
00781 purgeSites();
00782
00783 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00784 QuonMoveMessage* quonMoveMsg = new QuonMoveMessage("NODE_MOVE");
00785 quonMoveMsg->setCommand(NODE_MOVE);
00786 quonMoveMsg->setSender(thisSite->address);
00787 quonMoveMsg->setPosition(quonListMsg->getPosition());
00788 quonMoveMsg->setAOIsize(AOIWidth);
00789 quonMoveMsg->setNewPosition(thisSite->position);
00790 if(itSites->second->type == QBINDING) {
00791 quonMoveMsg->setIsBinding(true);
00792 }
00793 quonMoveMsg->setBitLength(QUONMOVE_L(quonMoveMsg));
00794 sendMessage(quonMoveMsg, itSites->second->address);
00795 }
00796 bytesPerSecond = 0.0;
00797 }
00798
00799 void Quon::handleNodeMove(QuonMoveMessage* quonMoveMsg)
00800 {
00801 RECORD_STATS(
00802 globalStatistics->addStdDev(
00803 "QuON: MoveDelay",
00804 SIMTIME_DBL(simTime()) - SIMTIME_DBL(quonMoveMsg->getCreationTime())
00805 );
00806 );
00807
00808 QuonAOI oldAOI(quonMoveMsg->getPosition(), quonMoveMsg->getAOIsize(), useSquareMetric);
00809 QuonAOI newAOI(quonMoveMsg->getNewPosition(), quonMoveMsg->getAOIsize(), useSquareMetric);
00810 if(useDynamicAOI) {
00811 QuonSiteMap::iterator itSites = Sites.find(quonMoveMsg->getSender().getKey());
00812 if(itSites != Sites.end() && itSites->second->AOIwidth < quonMoveMsg->getAOIsize()) {
00813 oldAOI.resize(itSites->second->AOIwidth);
00814 }
00815 }
00816
00817 addSite(quonMoveMsg->getNewPosition(), quonMoveMsg->getSender(), quonMoveMsg->getAOIsize(), quonMoveMsg->getIsBinding(), QDIRECT);
00818
00819 handleInvalidNode(quonMoveMsg);
00820 for(unsigned int i=0; i<quonMoveMsg->getNeighborHandleArraySize(); i++) {
00821 addSite(quonMoveMsg->getNeighborPosition(i), quonMoveMsg->getNeighborHandle(i), quonMoveMsg->getAOIsize());
00822 }
00823 classifySites();
00824
00825 synchronizeAppNeighbors();
00826 purgeSites();
00827
00828
00829 QuonListMessage* quonListMsg = new QuonListMessage("NEW_NEIGHBORS");
00830 quonListMsg->setCommand(NEW_NEIGHBORS);
00831 quonListMsg->setSender(thisSite->address);
00832 quonListMsg->setPosition(thisSite->position);
00833 quonListMsg->setAOIsize(AOIWidth);
00834
00835 quonListMsg->setNeighborHandleArraySize(Sites.size());
00836 quonListMsg->setNeighborPositionArraySize(Sites.size());
00837
00838 int i = 0;
00839 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00840 if(quonMoveMsg->getSender() != itSites->second->address &&
00841 !oldAOI.collide(itSites->second->position) &&
00842 newAOI.collide(itSites->second->position)) {
00843 quonListMsg->setNeighborHandle(i, itSites->second->address);
00844 quonListMsg->setNeighborPosition(i, itSites->second->position);
00845 ++i;
00846 }
00847 }
00848
00849 if(i > 0) {
00850 quonListMsg->setNeighborHandleArraySize(i);
00851 quonListMsg->setNeighborPositionArraySize(i);
00852 quonListMsg->setBitLength(QUONLIST_L(quonListMsg));
00853 sendMessage(quonListMsg, quonMoveMsg->getSender());
00854 }
00855 else {
00856 delete quonListMsg;
00857 }
00858 }
00859
00860 void Quon::handleNewNeighbors(QuonListMessage* quonListMsg)
00861 {
00862 addSite(quonListMsg->getPosition(), quonListMsg->getSender(), quonListMsg->getAOIsize(), false, QDIRECT);
00863
00864
00865 handleInvalidNode(quonListMsg);
00866 for(unsigned int i=0; i<quonListMsg->getNeighborHandleArraySize(); i++) {
00867 addSite(quonListMsg->getNeighborPosition(i), quonListMsg->getNeighborHandle(i), quonListMsg->getAOIsize());
00868 }
00869 classifySites();
00870
00871 synchronizeAppNeighbors();
00872 purgeSites();
00873 }
00874
00875 void Quon::handleNodeLeave(QuonListMessage* quonListMsg)
00876 {
00877 deleteSite(quonListMsg->getSender());
00878
00879 deleteAppNeighbor(quonListMsg->getSender());
00880
00881
00882 QuonSelfMessage* msg = new QuonSelfMessage("delete_timer");
00883 msg->setKey(quonListMsg->getSender().getKey());
00884 scheduleAt(simTime() + deleteTimeout, msg);
00885 deletedSites.insert(std::make_pair(quonListMsg->getSender().getKey(), msg));
00886
00887
00888 handleInvalidNode(quonListMsg);
00889 for(unsigned int i=0; i<quonListMsg->getNeighborHandleArraySize(); i++) {
00890 addSite(quonListMsg->getNeighborPosition(i), quonListMsg->getNeighborHandle(i), quonListMsg->getAOIsize(), true);
00891 }
00892 classifySites();
00893
00894 synchronizeAppNeighbors();
00895 purgeSites();
00896 }
00897
00898 void Quon::handleInvalidNode(QuonListMessage* quonListMsg)
00899 {
00900 for(unsigned int i=0; i<quonListMsg->getNeighborHandleArraySize(); i++) {
00901 if(deletedSites.find(quonListMsg->getNeighborHandle(i).getKey()) != deletedSites.end()) {
00902 QuonListMessage* quonLeaveMsg = new QuonListMessage("NODE_LEAVE");
00903 quonLeaveMsg->setCommand(NODE_LEAVE);
00904 quonLeaveMsg->setSender(quonListMsg->getNeighborHandle(i));
00905 quonLeaveMsg->setPosition(quonListMsg->getNeighborPosition(i));
00906 quonLeaveMsg->setAOIsize(AOIWidth);
00907 quonLeaveMsg->setNeighborHandleArraySize(Sites.size());
00908 quonLeaveMsg->setNeighborPositionArraySize(Sites.size());
00909 int i = 0;
00910 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00911 if(itSites->second->type == QBINDING) {
00912 quonLeaveMsg->setNeighborHandle(i, itSites->second->address);
00913 quonLeaveMsg->setNeighborPosition(i, itSites->second->position);
00914 ++i;
00915 }
00916 }
00917 quonLeaveMsg->setNeighborHandleArraySize(i);
00918 quonLeaveMsg->setNeighborPositionArraySize(i);
00919 quonLeaveMsg->setBitLength(QUONLIST_L(quonLeaveMsg));
00920 sendMessage(quonLeaveMsg, quonListMsg->getSender());
00921 }
00922 }
00923 }
00924
00925 void Quon::synchronizeAppNeighbors(QPurgeType purgeSoftSites)
00926 {
00927 GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
00928 gameMsg->setCommand(NEIGHBOR_UPDATE);
00929
00930 gameMsg->setRemoveNeighborArraySize(Sites.size());
00931 gameMsg->setAddNeighborArraySize(Sites.size());
00932 gameMsg->setNeighborPositionArraySize(Sites.size());
00933
00934 int remSize, addSize;
00935 remSize = addSize = 0;
00936 for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00937 if(itSites->second->type == QUNDEFINED && (purgeSoftSites == QPURGESOFT || !itSites->second->softNeighbor) && itSites->second->dirty) {
00938 gameMsg->setRemoveNeighbor(remSize, itSites->second->address);
00939 ++remSize;
00940 }
00941 else if(itSites->second->dirty) {
00942 gameMsg->setAddNeighbor(addSize, itSites->second->address);
00943 gameMsg->setNeighborPosition(addSize, itSites->second->position);
00944 itSites->second->dirty = false;
00945 ++addSize;
00946 }
00947 }
00948
00949 if(remSize > 0 || addSize > 0) {
00950 gameMsg->setRemoveNeighborArraySize(remSize);
00951 gameMsg->setAddNeighborArraySize(addSize);
00952 gameMsg->setNeighborPositionArraySize(addSize);
00953 sendToApp(gameMsg);
00954 }
00955 else {
00956 delete gameMsg;
00957 }
00958 }
00959
00960 void Quon::deleteAppNeighbor(NodeHandle node)
00961 {
00962 GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
00963 gameMsg->setCommand(NEIGHBOR_UPDATE);
00964 gameMsg->setRemoveNeighborArraySize(1);
00965 gameMsg->setAddNeighborArraySize(0);
00966 gameMsg->setNeighborPositionArraySize(0);
00967 gameMsg->setRemoveNeighbor(0, node);
00968 sendToApp(gameMsg);
00969 }
00970
00971 void Quon::sendToApp(cMessage* msg)
00972 {
00973
00974 if(debugOutput) {
00975 EV << "[Quon::sendToApp() @ " << thisNode.getAddress()
00976 << " (" << thisNode.getKey().toString(16) << ")]\n"
00977 << " Node " << thisSite->address.getAddress() << " sending " << msg->getName() << " to application."
00978 << endl;
00979 }
00980 send(msg, "appOut");
00981 }
00982
00983 void Quon::sendMessage(QuonMessage* quonMsg, NodeHandle destination)
00984 {
00985
00986 RECORD_STATS(
00987 switch(quonMsg->getCommand()) {
00988 case JOIN_REQUEST:
00989 joinRequestBytesSend += quonMsg->getByteLength();
00990 break;
00991 case JOIN_ACKNOWLEDGE:
00992 joinAcknowledgeBytesSend += quonMsg->getByteLength();
00993 break;
00994 case NODE_MOVE:
00995 nodeMoveBytesSend += quonMsg->getByteLength();
00996 break;
00997 case NEW_NEIGHBORS:
00998 newNeighborsBytesSend += quonMsg->getByteLength();
00999 break;
01000 case NODE_LEAVE:
01001 nodeLeaveBytesSend += quonMsg->getByteLength();
01002 break;
01003 }
01004 if(qstate == QREADY) {
01005 bytesPerSecond += quonMsg->getByteLength();
01006 }
01007 );
01008
01009
01010 if(debugOutput) {
01011 EV << "[Quon::sendMessage() @ " << thisNode.getAddress()
01012 << " (" << thisNode.getKey().toString(16) << ")]\n"
01013 << " Node " << thisSite->address.getAddress() << " sending " << quonMsg->getName() << " to " << destination.getAddress() << "."
01014 << endl;
01015 }
01016 sendMessageToUDP(destination, quonMsg);
01017 }
01018
01019 void Quon::setBootstrapedIcon()
01020 {
01021 if(ev.isGUI()) {
01022 switch(qstate) {
01023 case QUNINITIALIZED:
01024 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "red");
01025 getDisplayString().setTagArg("i", 1, "red");
01026 break;
01027 case QJOINING:
01028 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "yellow");
01029 getDisplayString().setTagArg("i", 1, "yellow");
01030 break;
01031 case QREADY:
01032 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "green");
01033 getDisplayString().setTagArg("i", 1, "green");
01034 break;
01035 }
01036 }
01037 }
01038
01039 void Quon::finishOverlay()
01040 {
01041 double overallBytesSend = joinRequestBytesSend
01042 + joinAcknowledgeBytesSend
01043 + nodeMoveBytesSend
01044 + newNeighborsBytesSend
01045 + nodeLeaveBytesSend;
01046 if(overallBytesSend != 0.0) {
01047
01048 globalStatistics->addStdDev("Quon: fraction of JOIN_REQUEST bytes sent ", joinRequestBytesSend / overallBytesSend);
01049 globalStatistics->addStdDev("Quon: fraction of JOIN_ACKNOWLEDGE bytes sent", joinAcknowledgeBytesSend / overallBytesSend);
01050 globalStatistics->addStdDev("Quon: fraction of NODE_MOVE bytes sent", nodeMoveBytesSend / overallBytesSend);
01051 globalStatistics->addStdDev("Quon: fraction of NEW_NEIGHBORS bytes sent", newNeighborsBytesSend / overallBytesSend);
01052 globalStatistics->addStdDev("Quon: fraction of NODE_LEAVE bytes sent", nodeLeaveBytesSend / overallBytesSend);
01053 }
01054 globalStatistics->addStdDev("Quon: max bytes/second sent", maxBytesPerSecondSend);
01055
01056
01057
01058
01059 if(secTimerCount != 0) {
01060 globalStatistics->addStdDev("Quon: average bytes/second sent", averageBytesPerSecondSend / (double) secTimerCount);
01061 globalStatistics->addStdDev("Quon: average direct-neighbor count", directNeighborCount / (double) secTimerCount);
01062 globalStatistics->addStdDev("Quon: average binding-neighbor count", bindingNeighborCount / (double) secTimerCount);
01063 globalStatistics->addStdDev("Quon: average soft-neighbor count", softNeighborCount / (double) secTimerCount);
01064
01065 globalStatistics->addStdDev("Quon: average AOI width", avgAOI / (double) secTimerCount);
01066 }
01067
01068 changeState(QUNINITIALIZED);
01069 }
01070
01071 QState Quon::getState()
01072 {
01073 Enter_Method_Silent();
01074 return qstate;
01075 }
01076
01077 double Quon::getAOI()
01078 {
01079 Enter_Method_Silent();
01080 return AOIWidth / (double)par("AOIBufferFactor");
01081 }
01082
01083 Vector2D Quon::getPosition()
01084 {
01085 Enter_Method_Silent();
01086 return thisSite->position;
01087 }
01088
01089 double Quon::getAreaDimension()
01090 {
01091 Enter_Method_Silent();
01092 return areaDimension;
01093 }
01094
01095 OverlayKey Quon::getKey()
01096 {
01097 Enter_Method_Silent();
01098 return thisSite->address.getKey();
01099 }
01100
01101 long Quon::getSoftNeighborCount()
01102 {
01103 Enter_Method_Silent();
01104 long temp = softConnections;
01105 softConnections = 0;
01106 return temp;
01107 }
01108
01109 Quon::~Quon()
01110 {
01111
01112 cancelAndDelete(join_timer);
01113 cancelAndDelete(sec_timer);
01114 cancelAndDelete(alive_timer);
01115 cancelAndDelete(backup_timer);
01116 cancelAndDelete(adaption_timer);
01117 delete thisSite;
01118 QuonSiteMap::iterator itSites = Sites.begin();
01119 while(itSites != Sites.end()) {
01120 delete itSites->second;
01121
01122 ++itSites++;
01123 }
01124 }