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