Quon.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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     // because of IPAddressResolver, we need to wait until interfaces are registered,
00034     // address auto-assignment takes place etc.
00035     if(stage != MIN_STAGE_OVERLAY) {
00036         return;
00037     }
00038 
00039     // fetch parameters
00040     minAOI = (double)par("minAOIWidth") + (double)par("AOIBuffer"); // FIXME: use buffer only where required
00041     maxAOI = (double)par("AOIWidth") + (double)par("AOIBuffer"); // FIXME: use buffer only where required
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     // determine wether we want dynamic AOI or not
00058     useDynamicAOI = connectionLimit > 0 && minAOI < maxAOI;
00059 
00060     // set node key and thisSite pointer
00061     thisNode.setKey(OverlayKey::random());
00062     thisSite = new QuonSite();
00063     thisSite->address = thisNode;
00064     thisSite->type = QTHIS;
00065 
00066     // initialize self-messages
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     // statistics
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     //rejoinCount = 0;
00087     avgAOI= 0 ;
00088 
00089     // watch some variables
00090     WATCH(thisSite->address);
00091     WATCH(thisSite->position);
00092     WATCH(AOIWidth);
00093     //WATCH_POINTER_MAP(Sites);
00094     //WATCH_POINTER_MAP(deletedSites);
00095     //WATCH_SET(Positions);
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     //WATCH(rejoinCount);
00108 
00109     // set initial state
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             // tell the application we are ready unless we are rejoining the overlay
00134             //if(rejoinCount == 0) {
00135             CompReadyMessage* readyMsg = new CompReadyMessage("OVERLAY_READY");
00136             readyMsg->setReady(true);
00137             readyMsg->setComp(getThisCompType());
00138             // TODO/FIXME: use overlay->sendMessageToAllComp(msg, getThisCompType())?
00139             sendToApp(readyMsg);
00140             //}
00141             // set initial AOI size
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     // debug output
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         //reset timer
00180         cancelEvent(join_timer);
00181         if(qstate != QREADY) {
00182             scheduleAt(simTime() + joinTimeout, msg);
00183             // handle event
00184             processJoinTimer();
00185         }
00186     }
00187     else if(msg->isName("sec_timer")) {
00188         //reset timer
00189         cancelEvent(sec_timer);
00190         scheduleAt(simTime() + 1, msg);
00191         // handle event
00192         processSecTimer();
00193     }
00194     else if(msg->isName("delete_timer")) {
00195         // handle event
00196         processDeleteTimer(msg);
00197     }
00198     else if(msg->isName("alive_timer")) {
00199         //reset timer
00200         cancelEvent(alive_timer);
00201         scheduleAt(simTime() + aliveTimeout, msg);
00202         // handle event
00203         processAliveTimer();
00204     }
00205     else if(msg->isName("backup_timer")) {
00206         //reset timer
00207         cancelEvent(backup_timer);
00208         scheduleAt(simTime() + backupIntervall, msg);
00209         // handle event
00210         processBackupTimer();
00211     }
00212 }
00213 
00214 void Quon::handleAppMessage(cMessage* msg)
00215 {
00216     GameAPIMessage* gameAPIMsg = dynamic_cast<GameAPIMessage*>(msg);
00217     if(gameAPIMsg != NULL) {
00218         // debug output
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         // debug output
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     // add node if he is not in the delete list OR has changed position since 
00306     // put in the delete list. don't add node if he has signled his leave himself
00307     // (i.e. his position in the delete list is 0,0)
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             // if dist is smaller than the most far binding candidate
00398             if( dist < bindingDistance[numBackups][quad] ){
00399             // Go through list of binding candidates until distance to current candidate
00400             // is greater than distance to new candidate (i.e. look where in the binding
00401             // candidate list the node belongs)
00402                 int backupPos = numBackups-1;
00403                 while( backupPos >= 0 && dist < bindingDistance[backupPos][quad] ){
00404                     // move old candidate one position back in the queue to make
00405                     // room for new candidate
00406                     bindingCandidates[backupPos+1][quad] = bindingCandidates[backupPos][quad];
00407                     bindingDistance[backupPos+1][quad] = bindingDistance[backupPos][quad];
00408                     --backupPos;
00409                 }
00410                 // place new candidate at appropriate position in candidate list
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         // Purge softNeighbors only if QPURGESOFT is set
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     // adjust AOIWidth
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         // TODO/FIXME: use overlay->sendMessageToAllComp(msg, getThisCompType())?
00522         sendToApp(readyMsg);
00523         if(Sites.size() > 0) {
00524             // generate node leave messages
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             // fill neighbors list
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             // update simple client
00616             deleteAppNeighbor(node);
00617             if(!rebuild) {
00618                 rebuild = true;
00619             }
00620         }
00621     }
00622     if(rebuild) {
00623         classifySites();
00624         // update simple client
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     // check if this is the only node in the overlay
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     // adapt aoi
00674     if(useDynamicAOI) {
00675         adaptAoI();
00676         classifySites();
00677     }
00678 
00679     Vector2D position = gameMsg->getPosition();
00680     // send position update to neighbors
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       // speedhack:
00704       // instead of building individual MoveMessages for every binding and softstate neighbor,
00705       // we just send all binding/soft to every other binding/soft neighbor and pretend we did not send  neighbors their own neighborslistentry
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     // update position
00729     updateThisSite(position);
00730     classifySites();
00731     // update simple client
00732     synchronizeAppNeighbors(QPURGESOFT);
00733     purgeSites(QPURGESOFT);
00734 }
00735 
00736 void Quon::handleEvent(GameAPIMessage* msg)
00737 {
00738     // send event to neighbors
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         // FIXME: Message length!
00744         sendMessage(quonMsg, itSites->second->address);
00745     }
00746 }
00747 
00748 void Quon::handleJoinRequest(QuonMessage* quonMsg)
00749 {
00750     Vector2D joinPosition = quonMsg->getPosition();
00751     // start with this node
00752     double min_dist = thisSite->position.distanceSqr(joinPosition);
00753     QuonSite* forwardSite = thisSite;
00754     // iterate through all neighbors
00755     for(QuonSiteMap::iterator itSites = Sites.begin(); itSites != Sites.end(); ++itSites) {
00756         if(itSites->second->position.distanceSqr(joinPosition) < min_dist) { //FIXME: use xy metric if desired?
00757             min_dist = itSites->second->position.distanceSqr(joinPosition);
00758             forwardSite = itSites->second;
00759         }
00760     }
00761 
00762     // do nothing and let node retry with new position if current position is illegal
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         // fill neighbors list
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     // add acceptor node
00796     changeState(QREADY);
00797     addSite(quonListMsg->getPosition(), quonListMsg->getSender(), quonListMsg->getAOIsize(), false, QDIRECT);
00798     // add new neighbors
00799     for(unsigned int i=0; i<quonListMsg->getNeighborHandleArraySize(); i++) {
00800         addSite(quonListMsg->getNeighborPosition(i), quonListMsg->getNeighborHandle(i), quonListMsg->getAOIsize());
00801     }
00802     classifySites();
00803     // update simple client
00804     synchronizeAppNeighbors();
00805     purgeSites();
00806     // contact new neighbors
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     // IF node was marked for deletetion, remove it from the delete list
00833     QDeleteMap::iterator delIt = deletedSites.find(quonMoveMsg->getSender().getKey());
00834     if( delIt != deletedSites.end() ){
00835         deletedSites.erase( delIt );
00836     }
00837 
00838     // Compute old and new AOI of moving node
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     // add new neighbors
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     // update simple client
00856     synchronizeAppNeighbors();
00857     purgeSites();
00858 
00859     // send new neighbors
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     // add new neighbors
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     // update simple client
00902     synchronizeAppNeighbors();
00903     purgeSites();
00904 }
00905 
00906 void Quon::handleNodeLeave(QuonListMessage* quonListMsg)
00907 {
00908     deleteSite(quonListMsg->getSender());
00909     // update simple client
00910     deleteAppNeighbor(quonListMsg->getSender());
00911 
00912     // insert into delete list
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     // add possible new neighbors
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     // update simple client
00925     synchronizeAppNeighbors();
00926     purgeSites();
00927 }
00928 
00929 // XXX FIXME Disabled, may cause exessive traffic
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     // debug output
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     // collect statistics
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     // debug output
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         // collect statistics in percent
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 //    We use our own time count to avoid rounding errors
01090 //    simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01091 //    if(time != 0.0) {
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         //globalStatistics->addStdDev("Quon: average rejoin count", rejoinCount);
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     // destroy self timer messages
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 }