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