Kademlia.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 
00023 #include "Kademlia.h"
00024 
00025 #include <assert.h>
00026 #include <algorithm>
00027 
00028 #include <IPAddressResolver.h>
00029 #include <IPvXAddress.h>
00030 #include <IInterfaceTable.h>
00031 #include <IPv4InterfaceData.h>
00032 #include "TopologyVis.h"
00033 #include <AbstractLookup.h>
00034 #include <LookupListener.h>
00035 #include <RpcMacros.h>
00036 #include <BootstrapList.h>
00037 
00038 #if 0
00039 #define BUCKET_CONSISTENCY(msg) \
00040     do {\
00041         bool stFull = false;\
00042         int z = 0;\
00043         if (siblingTable != NULL && siblingTable->size() > 0) {\
00044             stFull = siblingTable->isFull();\
00045             z = routingBucketIndex(siblingTable->back().getKey()) - 1;\
00046             if (routingTable[z - 1] != NULL && routingTable[z - 1]->size())\
00047                 breakpoint(#msg);\
00048         }\
00049         for (int y = 0; y < (z - 2); ++y) {\
00050             if ((routingTable[y] != NULL && routingTable[y]->size() > k) ||\
00051                 (routingTable[y] != NULL && routingTable[y]->size() && !stFull))\
00052                 breakpoint(#msg);\
00053         }\
00054     } while (false)
00055 #else
00056 #define BUCKET_CONSISTENCY(msg)
00057 #endif
00058 
00059 Define_Module(Kademlia);
00060 
00061 std::ostream& operator<<(std::ostream& os, const KademliaBucket* n)
00062 {
00063     if (n == NULL)
00064         os << "NULL";
00065     else {
00066         for (KademliaBucket::const_iterator i=n->begin(); i !=n->end(); i++) {
00067             os << *i << endl;
00068         }
00069         os << "last usage = " << n->getLastUsage()
00070            << ", last update = " << n->getLastUpdate();
00071     }
00072     return os;
00073 };
00074 
00075 class KademliaLookupListener : public LookupListener
00076 {
00077 private:
00078     Kademlia* overlay;
00079 public:
00080     KademliaLookupListener(Kademlia* overlay)
00081     {
00082         this->overlay = overlay;
00083     }
00084 
00085     virtual void lookupFinished(AbstractLookup *lookup)
00086     {
00087         overlay->lookupFinished(lookup->isValid());
00088         delete this;
00089     }
00090 };
00091 
00092 //-----------------------------------------------------------------------------
00093 
00094 void Kademlia::initializeOverlay(int stage)
00095 {
00096     if (stage != MIN_STAGE_OVERLAY)
00097         return;
00098 
00099     // Kademlia provides KBR services
00100     kbr = true;
00101 
00102     // setup kademlia parameters
00103     minSiblingTableRefreshInterval = par("minSiblingTableRefreshInterval");
00104     minBucketRefreshInterval = par("minBucketRefreshInterval");
00105     exhaustiveRefresh = par("exhaustiveRefresh");
00106     maxStaleCount = par("maxStaleCount");
00107     pingNewSiblings = par("pingNewSiblings");
00108 
00109     k = par("k");
00110     b = par("b");
00111     s = par("s");
00112 
00113     // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b )
00114     numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b);
00115 
00116     // init routing and sibling table
00117     siblingTable = new KademliaBucket(s * 5, NULL);
00118 
00119     // initialize pointers
00120     routingTable.assign(numBuckets, (KademliaBucket*)NULL);
00121 
00122     WATCH_VECTOR(*siblingTable);
00123     WATCH_VECTOR(routingTable);
00124 
00125     // self-message
00126     bucketRefreshTimer = new cMessage("bucketRefreshTimer");
00127 
00128     // statistics
00129     bucketRefreshCount = 0;
00130     siblingTableRefreshCount = 0;
00131     nodesReplaced = 0;
00132 
00133     comparator = NULL;
00134 }
00135 
00136 Kademlia::Kademlia()
00137 {
00138     siblingTable = NULL;
00139     comparator = NULL;
00140 }
00141 
00142 Kademlia::~Kademlia()
00143 {
00144     routingDeinit();
00145 
00146     replacementCache.clear();
00147     delete siblingTable;
00148     delete comparator;
00149     cancelAndDelete(bucketRefreshTimer);
00150 }
00151 
00152 void Kademlia::finishOverlay()
00153 {
00154     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00155     if (time < GlobalStatistics::MIN_MEASURED) return;
00156 
00157     globalStatistics->addStdDev("Kademlia: Nodes replaced in buckets/s",
00158                                 nodesReplaced / time);
00159     globalStatistics->addStdDev("Kademlia: Bucket Refreshes/s",
00160                                 bucketRefreshCount / time);
00161     globalStatistics->addStdDev("Kademlia: Sibling Table Refreshes/s",
00162                                 siblingTableRefreshCount / time);
00163 }
00164 
00165 void Kademlia::joinOverlay()
00166 {
00167     // remove current node handle from the bootstrap list
00168     if (!thisNode.getKey().isUnspecified()) {
00169         bootstrapList->removeBootstrapNode(thisNode);
00170     }
00171 
00172     // initialize routing
00173     routingDeinit();
00174     routingInit();
00175 
00176     TransportAddress handle = bootstrapList->getBootstrapNode();
00177 
00178     if (!handle.isUnspecified()) {
00179         // ping the bootstrap node to start bootstrapping
00180         pingNode(handle);
00181 
00182         /*
00183         FindNodeCall* findNodeCall = new FindNodeCall();
00184         findNodeCall->setLookupKey(handle.getKey());
00185         findNodeCall->setSrcNode(getThisNode());
00186         findNodeCall->setNumRedundantNodes(getMaxNumRedundantNodes());
00187         findNodeCall->setNumSiblings(getMaxNumSiblings());
00188         findNodeCall->setBitLength(FINDNODECALL_L(call));
00189 
00190         RECORD_STATS(numFindNodeSent++;
00191             bytesFindNodeSent += findNodeCall->getByteLength());
00192 
00193         sendUdpRpcCall(handle, findNodeCall);
00194          */
00195 
00196     } else {
00197         // we're the only node in the network
00198         state = READY;
00199         setOverlayReady(true);
00200 
00201         // schedule bucket refresh timer
00202         cancelEvent(bucketRefreshTimer);
00203         scheduleAt(simTime(), bucketRefreshTimer);
00204     }
00205 }
00206 
00207 //-----------------------------------------------------------------------------
00208 
00209 void Kademlia::routingInit()
00210 {
00211     // set join state
00212     state = INIT;
00213 
00214     setOverlayReady(false);
00215 
00216     // setup comparator
00217     comparator = new KeyDistanceComparator<KeyXorMetric>( thisNode.getKey() );
00218 
00219     siblingTable->setComparator(comparator);
00220 
00221     updateTooltip();
00222     BUCKET_CONSISTENCY(routingInit: end);
00223 }
00224 
00225 void Kademlia::routingDeinit()
00226 {
00227     // delete buckets
00228     for (uint32_t i = 0; i < routingTable.size(); i++) {
00229         if (routingTable[i] != NULL) {
00230             delete routingTable[i];
00231             routingTable[i] = NULL;
00232         }
00233     }
00234 
00235     if (siblingTable != NULL) {
00236         siblingTable->clear();
00237     }
00238 
00239     if (comparator != NULL) {
00240         delete comparator;
00241         comparator = NULL;
00242     }
00243 }
00244 
00245 int Kademlia::getMaxNumSiblings()
00246 {
00247     return s;
00248 }
00249 
00250 int Kademlia::getMaxNumRedundantNodes()
00251 {
00252     return k;
00253 }
00254 
00255 int Kademlia::routingBucketIndex(const OverlayKey& key, bool firstOnLayer)
00256 {
00257     // calculate XOR distance
00258     OverlayKey delta = key ^ getThisNode().getKey();
00259 
00260     // find first subinteger that is not zero...
00261     int i;
00262     for (i = key.getLength() - b; i >= 0 && delta.getBitRange(i, b) == 0;
00263          i -= b);
00264 
00265     if (i < 0)
00266         return -1;
00267 
00268     if (!firstOnLayer)
00269         return (i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1);
00270     else
00271         return (i / b) * ((1 << b) - 1) + (pow(2, b) - 2);
00272 }
00273 
00274 KademliaBucket* Kademlia::routingBucket(const OverlayKey& key, bool ensure)
00275 {
00276     // get bucket index
00277     int num = routingBucketIndex(key);
00278     if (num < 0)
00279         return NULL;
00280 
00281     // get bucket and allocate if necessary
00282     KademliaBucket* bucket = routingTable[ num ];
00283     if (bucket == NULL && ensure)
00284         bucket = routingTable[ num ] = new KademliaBucket( k, comparator );
00285 
00286     // return bucket
00287     return bucket;
00288 }
00289 
00290 bool Kademlia::routingAdd(const NodeHandle& handle, bool isAlive, simtime_t rtt)
00291 {
00292     BUCKET_CONSISTENCY(routingAdd: start);
00293     // never add unspecified node handles
00294     if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey() )
00295         return false;
00296 
00297     // bucket index
00298     KademliaBucket::iterator i;
00299     bool result = false;
00300 
00301     // convert node handle
00302     KademliaBucketEntry kadHandle = handle;
00303     kadHandle.setRtt(rtt);
00304     kadHandle.setLastSeen(simTime());
00305 
00306     /* check if node is already a sibling -----------------------------------*/
00307     if ((i = siblingTable->findIterator(handle.getKey()))
00308          != siblingTable->end()) {
00309         // not alive? -> do not change routing information
00310         if (isAlive) {
00311             if (kadHandle.getRtt() != i->getRtt()) {
00312                 siblingTable->setLastUpdate(simTime());
00313                 if (kadHandle.getRtt() == MAXTIME)
00314                     kadHandle.setRtt(i->getRtt());
00315             }
00316             // refresh sibling
00317             (*i) = kadHandle;
00318         }
00319         BUCKET_CONSISTENCY(routingAdd: node is sibling);
00320         return true;
00321     }
00322 
00323     /* check if node is already in a bucket ---------------------------------*/
00324     KademliaBucket* bucket = routingBucket(handle.getKey(), false);
00325     if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) )
00326             != bucket->end() ) {
00327         // not alive? -> do not change routing information
00328         if (isAlive) {
00329             if (kadHandle.getRtt() == MAXTIME) {
00330                 kadHandle.setRtt(i->getRtt());
00331             }
00332 
00333             // remove old handle
00334             bucket->erase(i);
00335             // re-add to tail
00336             bucket->push_back(kadHandle);
00337             bucket->setLastUpdate(simTime());
00338         }
00339         BUCKET_CONSISTENCY(routingAdd: node is in bucket);
00340         return true;
00341     }
00342 
00343     /* check if node can be added to the sibling list -----------------------*/
00344     if (siblingTable->isAddable(handle) ) {
00345 
00346         bool finished = false;
00347         int siblingPos = -1;
00348 
00349         // check if sibling list is full so a handle is preemted from the list
00350         if (siblingTable->isFull()) {
00351             // get handle thats about to be preempted
00352             KademliaBucketEntry oldHandle = siblingTable->back();
00353             assert(oldHandle.getKey() != kadHandle.getKey());
00354             // add handle to the sibling list
00355             siblingPos = siblingTable->add(kadHandle);
00356 
00357             // change, so that the preempted handle is added to a bucket
00358             kadHandle = oldHandle;
00359 
00360             // return always true, since the handle has been added
00361             result = true;
00362         } else {
00363             // simply add the handle and stop
00364             siblingPos = siblingTable->add(kadHandle);
00365 
00366             // don't need to add kadHandle also to regular buckets
00367             finished = true;
00368         }
00369         assert(siblingPos > -1);
00370 
00371         // ping new siblings
00372         if ((pingNewSiblings && !isAlive)) {
00373             pingNode(handle);
00374         }
00375 
00376         siblingTable->setLastUpdate(simTime());
00377 
00378         updateTooltip();
00379 
00380         // call update() for real siblings
00381         if (siblingPos < getMaxNumSiblings()) {
00382             if (siblingTable->size() > (uint32_t)getMaxNumSiblings()) {
00383                 // removed old sibling
00384                 NodeHandle& removedSibling = siblingTable->at(getMaxNumSiblings());
00385                 deleteOverlayNeighborArrow(removedSibling);
00386                 callUpdate(removedSibling, false);
00387             }
00388             // new sibling
00389             showOverlayNeighborArrow(handle, false,
00390                                      "m=m,50,100,50,100;ls=green,1");
00391             callUpdate(handle, true);
00392         }
00393 
00394         if (finished) {
00395             BUCKET_CONSISTENCY(routingAdd: node is now sibling);
00396             return true;
00397         }
00398     }
00399 
00400     /* add node to the appropriate bucket, if not full ---------------------*/
00401     bucket = routingBucket(kadHandle.getKey(), true);
00402     if (!bucket->isFull()) {
00403         EV << "[Kademlia::routingAdd()]\n"
00404            << "    Adding new node " << kadHandle
00405            << " to bucket " << routingBucketIndex(kadHandle.getKey())
00406            << endl;
00407 
00408         bucket->push_back(kadHandle);
00409         bucket->setLastUpdate(simTime());
00410         result = true;
00411     } else if (isAlive) {
00412         //TODO parameter for usage of replacement cache
00413         // save candidate, ping head,
00414         KademliaBucket::iterator it = bucket->begin();
00415         while (it != bucket->end() &&
00416                replacementCache.find(*it) != replacementCache.end()) {
00417             ++it;
00418         }
00419         if (it != bucket->end()) {
00420             replacementCache.insert(std::make_pair(*it, kadHandle));
00421             //TODO paper: probing should be delayed until useful messages are
00422             //there to send to head
00423             pingNode(*it);
00424         }
00425     }
00426 
00427     BUCKET_CONSISTENCY(routingAdd: end);
00428     return result;
00429 }
00430 
00431 bool Kademlia::routingRemove(const OverlayKey& key)
00432 {
00433     return routingTimeout(key, true);
00434 }
00435 
00436 bool Kademlia::routingTimeout(const OverlayKey& key, bool immediately)
00437 {
00438     BUCKET_CONSISTENCY(routingTimeout: start);
00439     // key unspecified? yes -> ignore
00440     if (key.isUnspecified())
00441         return false;
00442 
00443     // bucket index
00444     KademliaBucket::iterator i;
00445 
00446     /* check if the node is one of the siblings -----------------------------*/
00447     if ((i = siblingTable->findIterator(key)) != siblingTable->end()) {
00448 
00449         i->incStaleCount();
00450 
00451         if (i->getStaleCount() > maxStaleCount || immediately) {
00452             // remove from sibling table
00453             NodeHandle oldSibling = *i;
00454             siblingTable->erase(i);
00455 
00456             if (siblingTable->size() < (uint32_t)getMaxNumSiblings()) {
00457                 // no new replacement sibling
00458                 deleteOverlayNeighborArrow(oldSibling);
00459                 callUpdate(oldSibling, false);
00460             } else if (comparator->compare(oldSibling.getKey(),
00461                                siblingTable->at(getMaxNumSiblings() - 1).getKey()) < 0) {
00462                 // failed sibling was replaced by next closest node in siblingTable
00463                 deleteOverlayNeighborArrow(oldSibling);
00464                 callUpdate(oldSibling, false);
00465 
00466                 showOverlayNeighborArrow(siblingTable->at(getMaxNumSiblings() - 1),
00467                                          false, "m=m,50,100,50,100;ls=green,1");
00468                 callUpdate(siblingTable->at(getMaxNumSiblings() - 1), true);
00469             }
00470 
00471             updateTooltip();
00472 
00473             // lost last sibling?
00474             if (siblingTable->size() == 0) {
00475                 join();
00476                 return true;
00477             }
00478 
00479             BUCKET_CONSISTENCY(routingTimeout: is sibling);
00480 
00481             // try to refill with new closest contact
00482             refillSiblingTable();
00483 
00484             return true;
00485         }
00486     }
00487 
00488     /* check if node is already in a bucket ---------------------------------*/
00489     KademliaBucket* bucket = routingBucket(key, false);
00490     if (bucket != NULL && (i = bucket->findIterator(key) ) != bucket->end() ) {
00491 
00492         i->incStaleCount();
00493         std::map<NodeHandle, NodeHandle>::iterator it
00494                     = replacementCache.find(*i);
00495         if (i->getStaleCount() > maxStaleCount ||
00496             it != replacementCache.end() || immediately) {
00497             // remove from routing table
00498             bucket->erase(i);
00499         }
00500         if (it != replacementCache.end()) {
00501             routingAdd(it->second, true);
00502             nodesReplaced++;
00503             //EV << "node replaced" << endl;
00504         }
00505         BUCKET_CONSISTENCY(routingTimeout: is in bucket);
00506         return true;
00507     }
00508     BUCKET_CONSISTENCY(routingTimeout: end);
00509     return false;
00510 }
00511 
00512 void Kademlia::refillSiblingTable()
00513 {
00514     if (siblingTable->size() == 0 ||
00515         siblingTable->isFull())
00516         return;
00517 
00518     int index = routingBucketIndex(siblingTable->back().getKey()) - 1;
00519     assert(index > 0);
00520 
00521     while ((routingTable[index] == NULL ||
00522             routingTable[index]->empty()) &&
00523             index < (int)(OverlayKey::getLength() - 1)) {
00524         index++;
00525     }
00526     if (index < (int)OverlayKey::getLength() &&
00527             routingTable[index] != NULL && routingTable[index]->size()) {
00528         KademliaBucket sortedBucket(k, comparator);
00529         for (uint32_t i = 0; i < routingTable[index]->size(); ++i)
00530             sortedBucket.add(routingTable[index]->at(i));
00531         siblingTable->add(sortedBucket.front());
00532         // no need to callUpdate(), because s < siblingTable->size(), thus
00533         // new sibling table entry is no real sibling
00534         routingTable[index]->
00535         erase(routingTable[index]->
00536               findIterator(sortedBucket.front().getKey()));
00537         assert(siblingTable->isFull());
00538         BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable());
00539     }
00540 }
00541 
00542 void Kademlia::setBucketUsage(const OverlayKey& key)
00543 {
00544     KademliaBucket* bucket = routingBucket(key, true);
00545 
00546     if (bucket)
00547         bucket->setLastUsage(simTime());
00548 
00549 /*
00550     if (!siblingTable->size() || ((siblingTable->back().getKey() ^ thisNode.getKey()) >=
00551                                   (key ^ thisNode.getKey())))
00552         siblingTable->setLastUsage(simTime());
00553  */
00554 
00555     if (((siblingTable->size() + 1) < (uint32_t)getMaxNumSiblings())
00556         || ((siblingTable->at(getMaxNumSiblings() - 2).getKey() ^ thisNode.getKey())
00557                 >= (key ^ thisNode.getKey()))) {
00558         siblingTable->setLastUsage(simTime());
00559     }
00560 
00561 }
00562 
00563 bool Kademlia::isSiblingFor(const NodeHandle& node, const OverlayKey& key,
00564                             int numSiblings, bool* err)
00565 {
00566     if (key.isUnspecified())
00567         error("Kademlia::isSiblingFor(): key is unspecified!");
00568 
00569     if (state != READY) {
00570         *err = true;
00571         return false;
00572     }
00573 
00574     if (numSiblings > getMaxNumSiblings()) {
00575         opp_error("Kademlia::isSiblingFor(): numSiblings too big!");
00576     }
00577 
00578     // set default number of siblings to consider
00579     if (numSiblings == -1) {
00580         numSiblings = getMaxNumSiblings();
00581     }
00582 
00583     if (numSiblings == 0) {
00584         *err = false;
00585         return (node.getKey() == key);
00586     }
00587 
00588     if (siblingTable->size() < (uint)numSiblings) {
00589         *err = false;
00590         return true;
00591     }
00592 
00593     if ((thisNode.getKey() ^ key) > (thisNode.getKey() ^ siblingTable->back().getKey())) {
00594         *err = true;
00595         return false;
00596     }
00597 
00598     KeyDistanceComparator<KeyXorMetric>* comp =
00599         new KeyDistanceComparator<KeyXorMetric>(key);
00600 
00601     // create result vector
00602     NodeVector* result = new NodeVector(numSiblings, comp);
00603 
00604     for (KademliaBucket::iterator i=siblingTable->begin();
00605          i != siblingTable->end(); i++) {
00606         result->add( *i);
00607     }
00608 
00609     // add local node
00610     result->add(thisNode);
00611 
00612     *err = false;
00613     delete comp;
00614 
00615     if (result->contains(node.getKey())) {
00616         delete result;
00617         return true;
00618     } else {
00619         delete result;
00620         assert(!(numSiblings == 1 && key == node.getKey()));
00621         return false;
00622     }
00623 }
00624 
00625 bool Kademlia::handleFailedNode(const TransportAddress& failed)
00626 {
00627     assert(!failed.isUnspecified());
00628 
00629     KademliaBucket::iterator i;
00630     // check sibling table
00631     for (i = siblingTable->begin(); i != siblingTable->end(); ++i) {
00632         if (failed == *i) break;
00633     }
00634 
00635     if (i != siblingTable->end()) {
00636         // remove from sibling table
00637         NodeHandle oldSibling = *i;
00638         siblingTable->erase(i);
00639 
00640         if (siblingTable->size() < (uint32_t)getMaxNumSiblings()) {
00641             // no new replacement sibling
00642             deleteOverlayNeighborArrow(oldSibling);
00643             callUpdate(oldSibling, false);
00644         } else if (comparator->compare(oldSibling.getKey(),
00645                            siblingTable->at(getMaxNumSiblings() - 1).getKey()) < 0) {
00646             // failed sibling was replaced by next closest node in siblingTable
00647             deleteOverlayNeighborArrow(oldSibling);
00648             callUpdate(oldSibling, false);
00649 
00650             showOverlayNeighborArrow(siblingTable->at(getMaxNumSiblings() - 1),
00651                                      false, "m=m,50,100,50,100;ls=green,1");
00652             callUpdate(siblingTable->at(getMaxNumSiblings() - 1), true);
00653         }
00654 
00655         updateTooltip();
00656 
00657         // try to refill with new closest contact
00658         refillSiblingTable();
00659     } else {
00660         // check buckets
00661         uint32_t m;
00662         for (m = 0; m < routingTable.size(); ++m) {
00663             if (routingTable[m] != NULL) {
00664                 for (i = routingTable[m]->begin(); i != routingTable[m]->end();
00665                      ++i) {
00666                     if (failed == *i) {
00667                         // remove from routing table
00668                         routingTable[m]->erase(i);
00669                         return (siblingTable->size() != 0);
00670                     }
00671                 }
00672             }
00673         }
00674     }
00675     return (siblingTable->size() != 0);
00676 }
00677 
00678 NodeVector* Kademlia::findNode(const OverlayKey& key, int numRedundantNodes,
00679                                int numSiblings, BaseOverlayMessage* msg)
00680 {
00681     if ((numRedundantNodes > getMaxNumRedundantNodes()) ||
00682             (numSiblings > getMaxNumSiblings())) {
00683 
00684         opp_error("(Kademlia::findNode()) numRedundantNodes or numSiblings "
00685                   "too big!");
00686     }
00687 
00688     if (numRedundantNodes < 2) {
00689         throw cRuntimeError("Kademlia::findNode(): For Kademlia "
00690                                 "redundantNodes must be at least 2 "
00691                                 "and lookupMerge should be true!");
00692     }
00693 
00694     // create temporary comparator
00695     KeyDistanceComparator<KeyXorMetric>* comp =
00696         new KeyDistanceComparator<KeyXorMetric>( key );
00697 
00698     // select result set size
00699     bool err;
00700     int resultSize;
00701 
00702     if (numSiblings < 0) {
00703         // exhaustive iterative doesn't care about siblings
00704         resultSize = numRedundantNodes;
00705     } else {
00706         resultSize = isSiblingFor(thisNode, key, numSiblings, &err) ?
00707                 (numSiblings ? numSiblings : 1) : numRedundantNodes;
00708     }
00709     assert(numSiblings || numRedundantNodes);
00710 
00711     NodeVector* result = new NodeVector(resultSize, comp);
00712 
00713     if (siblingTable->isEmpty()) {
00714         result->add(thisNode);
00715         delete comp;
00716         return result;
00717     }
00718 
00719     // add items from buckets
00720     int index;
00721     int mainIndex = routingBucketIndex(key);
00722     int startIndex = routingBucketIndex(key, true);
00723     int endIndex = routingBucketIndex(siblingTable->back().getKey());
00724 
00725     // add nodes from best fitting bucket
00726     if (mainIndex != -1) {
00727         KademliaBucket* bucket = routingTable[mainIndex];
00728         if (bucket != NULL && bucket->size()) {
00729             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00730                 result->add(*i);
00731                 //EV << "Kademlia::findNode(): Adding "
00732                 //   << *i << " from bucket " << mainIndex << endl;
00733             }
00734         }
00735     }
00736 
00737     // add most fitting buckets
00738     if (startIndex >= endIndex || !result->isFull()) {
00739         for (index = startIndex; index >= endIndex; --index) {
00740             // old code...
00741             /*
00742             for (int i = 1; !result->isFull() && i < numBuckets * 3; i++) {
00743                 int index = mainIndex + (((i & 1) == 1) ? -1 : 1) * (i / 2);
00744                 if (index < 0 || index >= numBuckets)
00745                     continue;
00746             */
00747 
00748             // add bucket to result vector
00749             if (index == mainIndex) continue;
00750             KademliaBucket* bucket = routingTable[index];
00751             if (bucket != NULL && bucket->size()) {
00752                 for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00753                     result->add(*i);
00754                     //EV << "Kademlia::routingGetClosestNodes(): Adding "
00755                     //   << *i << " from bucket " << index << endl;
00756                 }
00757             }
00758         }
00759 
00760         // add nodes from sibling table
00761         for (KademliaBucket::iterator i = siblingTable->begin();
00762              i != siblingTable->end(); i++) {
00763             result->add(*i);
00764         }
00765         // add local node
00766         result->add(thisNode);
00767     }
00768 
00769     // add more distant buckets
00770     for (index = mainIndex + 1; !result->isFull() && index < numBuckets;
00771          ++index) {
00772         // add bucket to result vector
00773         KademliaBucket* bucket = routingTable[index];
00774         if (bucket != NULL && bucket->size()) {
00775             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00776                 result->add(*i);
00777                 //EV << "[Kademlia::routingGetClosestNodes()]\n"
00778                 //   << "    Adding " << *i << " from bucket " << index
00779                 //   << endl;
00780             }
00781         }
00782     }
00783 
00784     delete comp;
00785 
00786     return result;
00787 }
00788 
00789 //-----------------------------------------------------------------------------
00790 
00791 
00792 void Kademlia::handleTimerEvent(cMessage* msg)
00793 {
00794     if (msg == bucketRefreshTimer) {
00795         handleBucketRefreshTimerExpired();
00796     }
00797 }
00798 
00799 //In Kademlia this method is used to maintain the routing table.
00800 bool Kademlia::handleRpcCall(BaseCallMessage* msg)
00801 {
00802     RPC_SWITCH_START(msg)
00803     RPC_ON_CALL(Ping) {
00804         // add active node
00805         OverlayCtrlInfo* ctrlInfo =
00806             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00807         routingAdd(ctrlInfo->getSrcRoute(), true );
00808         break;
00809     }
00810     RPC_ON_CALL(FindNode)
00811     {
00812         // add active node
00813         OverlayCtrlInfo* ctrlInfo =
00814             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00815         routingAdd(ctrlInfo->getSrcRoute(), true);
00816         break;
00817     }
00818     RPC_SWITCH_END()
00819     return false;
00820 }
00821 
00822 //In Kademlia this method is used to maintain the routing table.
00823 void Kademlia::handleRpcResponse(BaseResponseMessage* msg,
00824                                  cPolymorphic* context, int rpcId,
00825                                  simtime_t rtt)
00826 {
00827     OverlayCtrlInfo* ctrlInfo =
00828         dynamic_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00829     NodeHandle srcRoute = (ctrlInfo ? ctrlInfo->getSrcRoute()
00830                                     : msg->getSrcNode());
00831 
00832     RPC_SWITCH_START(msg)
00833         RPC_ON_RESPONSE(Ping) {
00834             if (state == INIT) {
00835                 // schedule bucket refresh timer
00836                 cancelEvent(bucketRefreshTimer);
00837                 scheduleAt(simTime(), bucketRefreshTimer);
00838                 state = JOIN;
00839             }
00840 
00841             // delete replacement candidate //TODO
00842             replacementCache.erase(srcRoute);
00843         }
00844         RPC_ON_RESPONSE(FindNode)
00845         {
00846             // add active node
00847             if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
00848                 defaultRoutingType == FULL_RECURSIVE_ROUTING ||
00849                 defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
00850                 rtt = MAXTIME;
00851             }
00852             setBucketUsage(srcRoute.getKey());
00853 
00854             // add inactive nodes
00855             for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
00856                 routingAdd(_FindNodeResponse->getClosestNodes(i), false);
00857             break;
00858         }
00859     RPC_SWITCH_END()
00860 
00861     // add node that responded
00862     routingAdd(srcRoute, true, rtt);
00863 }
00864 
00865 // In Kademlia this method is used to maintain the routing table.
00866 void Kademlia::handleRpcTimeout(BaseCallMessage* msg,
00867                                 const TransportAddress& dest,
00868                                 cPolymorphic* context, int rpcId,
00869                                 const OverlayKey& destKey)
00870 {
00871     if (dest.isUnspecified()) return;
00872     try {
00873         RPC_SWITCH_START(msg)
00874         RPC_ON_CALL(Ping) {
00875             if (state == INIT) {
00876                 join();
00877                 return;
00878             }
00879 
00880             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
00881             routingTimeout(handle.getKey());
00882 
00883             // remove node from replacementCache
00884             std::map<NodeHandle, NodeHandle>::iterator it
00885                 = replacementCache.find(handle);
00886             if (it != replacementCache.end()) {
00887                 replacementCache.erase(it);
00888             }
00889 
00890             break;
00891         }
00892         RPC_ON_CALL(FindNode) {
00893             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
00894             routingTimeout(handle.getKey());
00895             setBucketUsage(handle.getKey());
00896             break;
00897         }
00898         RPC_SWITCH_END()
00899     } catch (...) {
00900         EV << "[Kademlia:handleRpcTimout() @ " << thisNode.getAddress()
00901            << " (" << thisNode.getKey().toString(16) << ")]\n"
00902            << "    ERROR: RPC timeout without key ("
00903            << msg << " -> " << dest << ")" << endl;
00904         return;
00905     }
00906 }
00907 
00908 void Kademlia::lookupFinished(bool isValid)
00909 {
00910     if (state == JOIN) {
00911         cancelEvent(bucketRefreshTimer);
00912 
00913         if (siblingTable->size() == 0) {
00914             // initial lookup failed - get new bootstrap node
00915             join();
00916             return;
00917         }
00918 
00919         scheduleAt(simTime(), bucketRefreshTimer);
00920 
00921         state = READY;
00922         setOverlayReady(true);
00923     }
00924 }
00925 
00926 // handle a expired bucket refresh timer
00927 void Kademlia::handleBucketRefreshTimerExpired()
00928 {
00929     // refresh buckets
00930     if (state != READY || (((simTime() - siblingTable->getLastUsage()) >
00931                             minSiblingTableRefreshInterval))) {
00932         if (exhaustiveRefresh) {
00933             // TODO: replace redundantNodes by k?
00934             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
00935                  getThisNode().getKey(), iterativeLookupConfig.redundantNodes,
00936                  0, 0, new KademliaLookupListener(this));
00937         } else {
00938             createLookup()->lookup(getThisNode().getKey(), s, 0, 0,
00939                                    new KademliaLookupListener(this));
00940         }
00941         ++siblingTableRefreshCount;
00942     }
00943 
00944     if (state == READY) {
00945         if (siblingTable->size()) {
00946             // get bit index of most significant digit that differs
00947             // from our next sibling's key to prevent us from refreshing
00948             // buckets, which can't contain any nodes
00949             int32_t diff = OverlayKey::getLength() - b*(getThisNode().getKey().
00950                 sharedPrefixLength(siblingTable->front().getKey(), b) + 1);
00951             int bucketsRefreshedPerTask = 0;
00952             for (int32_t i = OverlayKey::getLength() - b; i >= diff; i -=b ) {
00953                 for (int32_t d=0; d < ((1 << b) - 1); d++) {
00954                     int32_t index = (i / b) * ((1 << b) - 1) + d;
00955                     if ((routingTable[index] == NULL) ||
00956                         ((simTime() - routingTable[index]->getLastUsage()) >
00957                         minBucketRefreshInterval)) {
00958 
00959                         OverlayKey refreshKey =
00960                             getThisNode().getKey() ^ (OverlayKey(d+1) << i);
00961 
00962                         if (exhaustiveRefresh) {
00963                             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
00964                                 refreshKey, iterativeLookupConfig.redundantNodes,
00965                                 0, 0, new KademliaLookupListener(this));
00966                         } else {
00967                             createLookup()->lookup(refreshKey, s, 0, 0,
00968                                              new KademliaLookupListener(this));
00969                         }
00970 
00971                         ++bucketsRefreshedPerTask;
00972                         ++bucketRefreshCount;
00973                         setBucketUsage(refreshKey);
00974                     }
00975                 }
00976             }
00977             RECORD_STATS(globalStatistics->recordOutVector(
00978                                    "Kademlia: Buckets Refreshed Per Task",
00979                                    bucketsRefreshedPerTask));
00980         }
00981         // schedule next bucket refresh process
00982         cancelEvent(bucketRefreshTimer);
00983         scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval,
00984                         minBucketRefreshInterval) / 10.0), bucketRefreshTimer);
00985     }
00986 }
00987 
00988 //virtual public: xor metric
00989 OverlayKey Kademlia::distance(const OverlayKey& x, const OverlayKey& y) const
00990 {
00991     return x^y;
00992 }
00993 
00994 void Kademlia::updateTooltip()
00995 {
00996     if (ev.isGUI()) {
00997         std::stringstream ttString;
00998 
00999         // show our nodeId in a tooltip
01000         ttString << "This: " << thisNode << endl << "Siblings: "
01001                  << siblingTable->size();
01002 
01003         getParentModule()->getParentModule()->getDisplayString().
01004         setTagArg("tt", 0, ttString.str().c_str());
01005         getParentModule()->getDisplayString().
01006         setTagArg("tt", 0, ttString.str().c_str());
01007         getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
01008     }
01009 }
01010 

Generated on Tue Sep 8 17:26:53 2009 for OverSim by  doxygen 1.5.8