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 #include "KademliaMessage_m.h"
00025 
00026 #include <assert.h>
00027 #include <algorithm>
00028 
00029 #include <IPAddressResolver.h>
00030 #include <IPvXAddress.h>
00031 #include <IInterfaceTable.h>
00032 #include <IPv4InterfaceData.h>
00033 #include "TopologyVis.h"
00034 #include <AbstractLookup.h>
00035 #include <LookupListener.h>
00036 #include <RpcMacros.h>
00037 #include <BootstrapList.h>
00038 
00039 #if 0
00040 #define BUCKET_CONSISTENCY(msg) \
00041     do {\
00042         bool stFull = false;\
00043         int z = 0;\
00044         if (siblingTable != NULL && siblingTable->size() > 0) {\
00045             stFull = siblingTable->isFull();\
00046             z = routingBucketIndex(siblingTable->back().getKey()) - 1;\
00047             if (routingTable[z - 1] != NULL && routingTable[z - 1]->size())\
00048                 breakpoint(#msg);\
00049         }\
00050         for (int y = 0; y < (z - 2); ++y) {\
00051             if ((routingTable[y] != NULL && routingTable[y]->size() > k) ||\
00052                 (routingTable[y] != NULL && routingTable[y]->size() && !stFull))\
00053                 breakpoint(#msg);\
00054         }\
00055     } while (false)
00056 #else
00057 #define BUCKET_CONSISTENCY(msg)
00058 #endif
00059 
00060 Define_Module(Kademlia);
00061 
00062 std::ostream& operator<<(std::ostream& os, const KademliaBucket* n)
00063 {
00064     if (n == NULL)
00065         os << "NULL";
00066     else {
00067         for (KademliaBucket::const_iterator i=n->begin(); i !=n->end(); i++) {
00068             os << *i << endl;
00069         }
00070         os << "last usage = " << n->getLastUsage();
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     siblingPingInterval = par("siblingPingInterval");
00106     exhaustiveRefresh = par("exhaustiveRefresh");
00107     maxStaleCount = par("maxStaleCount");
00108     pingNewSiblings = par("pingNewSiblings");
00109     enableReplacementCache = par("enableReplacementCache");
00110     replacementCachePing = par("replacementCachePing");
00111     replacementCandidates = par("replacementCandidates");
00112     secureMaintenance = par("secureMaintenance");
00113     newMaintenance = par("newMaintenance");
00114 
00115     // R/Kademlia
00116     activePing = par("activePing");
00117     proximityRouting = par("proximityRouting");
00118     proximityNeighborSelection = par("proximityNeighborSelection");
00119     altRecMode = recordRoute = par("altRecMode");
00120 
00121     k = par("k");
00122     b = par("b");
00123     s = par("s");
00124 
00125     siblingRefreshNodes = par("siblingRefreshNodes");
00126 
00127     if (siblingRefreshNodes <= 0) {
00128         siblingRefreshNodes = 5 * s;
00129     }
00130 
00131     bucketRefreshNodes = par("bucketRefreshNodes");
00132 
00133     if (bucketRefreshNodes <= 0) {
00134         bucketRefreshNodes = iterativeLookupConfig.redundantNodes;
00135     }
00136 
00137     // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b )
00138     numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b);
00139 
00140     // init routing and sibling table
00141     siblingTable = new KademliaBucket(s * 5, NULL);
00142 
00143     // initialize pointers
00144     routingTable.assign(numBuckets, (KademliaBucket*)NULL);
00145 
00146     WATCH_VECTOR(*siblingTable);
00147     WATCH_VECTOR(routingTable);
00148 
00149     // self-message
00150     bucketRefreshTimer = new cMessage("bucketRefreshTimer");
00151     siblingPingTimer = new cMessage("siblingPingTimer");
00152 
00153     // statistics
00154     bucketRefreshCount = 0;
00155     siblingTableRefreshCount = 0;
00156     nodesReplaced = 0;
00157 
00158     comparator = NULL;
00159 }
00160 
00161 Kademlia::Kademlia()
00162 {
00163     siblingTable = NULL;
00164     comparator = NULL;
00165     bucketRefreshTimer = NULL;
00166     siblingPingTimer = NULL;
00167 }
00168 
00169 Kademlia::~Kademlia()
00170 {
00171     routingDeinit();
00172 
00173     delete siblingTable;
00174     delete comparator;
00175     cancelAndDelete(bucketRefreshTimer);
00176     cancelAndDelete(siblingPingTimer);
00177 }
00178 
00179 void Kademlia::finishOverlay()
00180 {
00181     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00182     if (time < GlobalStatistics::MIN_MEASURED) return;
00183 
00184     globalStatistics->addStdDev("Kademlia: Nodes replaced in buckets/s",
00185                                 nodesReplaced / time);
00186     globalStatistics->addStdDev("Kademlia: Bucket Refreshes/s",
00187                                 bucketRefreshCount / time);
00188     globalStatistics->addStdDev("Kademlia: Sibling Table Refreshes/s",
00189                                 siblingTableRefreshCount / time);
00190 }
00191 
00192 void Kademlia::sendSiblingFindNodeCall(const TransportAddress& dest)
00193 {
00194     FindNodeCall* call = new FindNodeCall("FindNodeCall");
00195     call->setExhaustiveIterative(true);
00196     call->setLookupKey(thisNode.getKey());
00197     call->setNumRedundantNodes(siblingRefreshNodes);
00198     call->setNumSiblings(getMaxNumSiblings());
00199     call->setBitLength(FINDNODECALL_L(call));
00200     sendUdpRpcCall(dest, call);
00201 }
00202 
00203 void Kademlia::joinOverlay()
00204 {
00205     // remove current node handle from the bootstrap list
00206     if (!thisNode.getKey().isUnspecified()) {
00207         bootstrapList->removeBootstrapNode(thisNode);
00208     }
00209 
00210     // initialize routing
00211     routingDeinit();
00212     routingInit();
00213 
00214     TransportAddress handle = bootstrapList->getBootstrapNode();
00215 
00216     if (!handle.isUnspecified()) {
00217         if (secureMaintenance) {
00218             sendSiblingFindNodeCall(handle);
00219         } else {
00220             // ping the bootstrap node to start bootstrapping
00221             pingNode(handle);
00222         }
00223     } else {
00224         // we're the only node in the network
00225         state = READY;
00226         setOverlayReady(true);
00227 
00228         // schedule bucket refresh timer
00229         cancelEvent(bucketRefreshTimer);
00230         scheduleAt(simTime(), bucketRefreshTimer);
00231         cancelEvent(siblingPingTimer);
00232         scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
00233     }
00234 }
00235 
00236 //-----------------------------------------------------------------------------
00237 
00238 void Kademlia::routingInit()
00239 {
00240     // set join state
00241     state = INIT;
00242 
00243     setOverlayReady(false);
00244 
00245     // setup comparator
00246     comparator = new KeyDistanceComparator<KeyXorMetric>(thisNode.getKey());
00247 
00248     siblingTable->setComparator(comparator);
00249 
00250     updateTooltip();
00251     BUCKET_CONSISTENCY(routingInit: end);
00252 }
00253 
00254 void Kademlia::routingDeinit()
00255 {
00256     // delete buckets
00257     for (uint32_t i = 0; i < routingTable.size(); i++) {
00258         if (routingTable[i] != NULL) {
00259             delete routingTable[i];
00260             routingTable[i] = NULL;
00261         }
00262     }
00263 
00264     if (siblingTable != NULL) {
00265         siblingTable->clear();
00266     }
00267 
00268     if (comparator != NULL) {
00269         delete comparator;
00270         comparator = NULL;
00271     }
00272 }
00273 
00274 int Kademlia::getMaxNumSiblings()
00275 {
00276     return s;
00277 }
00278 
00279 int Kademlia::getMaxNumRedundantNodes()
00280 {
00281     return k;
00282 }
00283 
00284 int Kademlia::routingBucketIndex(const OverlayKey& key, bool firstOnLayer)
00285 {
00286     // calculate XOR distance
00287     OverlayKey delta = key ^ getThisNode().getKey();
00288 
00289     // find first subinteger that is not zero...
00290     int i;
00291     for (i = key.getLength() - b; i >= 0 && delta.getBitRange(i, b) == 0;
00292          i -= b);
00293 
00294     if (i < 0)
00295         return -1;
00296 
00297     if (!firstOnLayer)
00298         return (i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1);
00299     else
00300         return (i / b) * ((1 << b) - 1) + (pow(2, b) - 2);
00301 }
00302 
00303 KademliaBucket* Kademlia::routingBucket(const OverlayKey& key, bool ensure)
00304 {
00305     // get bucket index
00306     int num = routingBucketIndex(key);
00307     if (num < 0)
00308         return NULL;
00309 
00310     // get bucket and allocate if necessary
00311     KademliaBucket* bucket = routingTable[ num ];
00312     if (bucket == NULL && ensure)
00313         bucket = routingTable[ num ] = new KademliaBucket( k, comparator );
00314 
00315     // return bucket
00316     return bucket;
00317 }
00318 
00319 bool Kademlia::routingAdd(const NodeHandle& handle, bool isAlive,
00320                           simtime_t rtt, bool maintenanceLookup)
00321 {
00322     BUCKET_CONSISTENCY(routingAdd: start);
00323     // never add unspecified node handles
00324     if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey()) {
00325         return false;
00326     }
00327 
00328 
00329     // bucket index
00330     KademliaBucket::iterator i;
00331     bool result = false;
00332     bool authenticated = (isAlive && (rtt != MAXTIME));
00333 
00334     bool needsRtt = (activePing && ((rtt == MAXTIME) ? true : false));
00335 
00336     // convert node handle
00337     KademliaBucketEntry kadHandle = handle;
00338     kadHandle.setRtt(rtt);
00339     kadHandle.setLastSeen(simTime());
00340 
00341     /* check if node is already a sibling -----------------------------------*/
00342     if ((i = siblingTable->findIterator(handle.getKey()))
00343          != siblingTable->end()) {
00344         // not alive? -> do not change routing information
00345         if (isAlive) {
00346             if (!secureMaintenance || authenticated) {
00347                 if (kadHandle.getRtt() == MAXTIME) {
00348                     kadHandle.setRtt(i->getRtt());
00349                 }
00350                 // refresh sibling
00351                 (*i) = kadHandle;
00352             } else {
00353                 if (maintenanceLookup) {
00354                     return false;
00355                 }
00356 
00357                 if ((i->getIp() != handle.getIp()) ||
00358                     (i->getPort() != handle.getPort())) {
00359                     // sibling could have changed transport address
00360                     // ping new address for authentication
00361                     pingNode(handle);
00362                     return false;
00363                 }
00364             }
00365         }
00366         BUCKET_CONSISTENCY(routingAdd: node is sibling);
00367         return true;
00368     }
00369 
00370     /* check if node is already in a bucket ---------------------------------*/
00371     KademliaBucket* bucket = routingBucket(handle.getKey(), false);
00372     if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) )
00373             != bucket->end() ) {
00374         // not alive? -> do not change routing information
00375         if (isAlive) {
00376             if (!secureMaintenance || authenticated) {
00377                 if (kadHandle.getRtt() == MAXTIME) {
00378                     kadHandle.setRtt(i->getRtt());
00379                 }
00380 
00381                 // R/Kademlia
00382                 if (needsRtt && (kadHandle.getRtt() == MAXTIME)) {
00383                     Prox prox =
00384                         neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
00385                                                this, NULL);
00386                     if (prox != Prox::PROX_SELF &&
00387                         prox != Prox::PROX_UNKNOWN &&
00388                         prox != Prox::PROX_TIMEOUT) {
00389                         kadHandle.setProx(prox);
00390                         //routingAdd(handle, true, prox.proximity);//ctrlInfo->getSrcRoute() //TODO
00391                     } /*else if (prox == Prox::PROX_TIMEOUT) {
00392                         // remove from bucket
00393                         bucket->erase(i);
00394                         return false;
00395                     }*/ //TODO inform NC that node is alive
00396                     else {
00397                         return false;
00398                     }
00399                 }
00400 
00401                 // remove old handle
00402                 bucket->erase(i);
00403                 // re-add to tail
00404                 bucket->push_back(kadHandle);
00405             } else {
00406                 if (maintenanceLookup) {
00407                     return false;
00408                 }
00409 
00410                 if ((i->getIp() != handle.getIp()) ||
00411                     (i->getPort() != handle.getPort())) {
00412                     // sibling could have changed transport address
00413                     // ping new address for authentication
00414                     pingNode(handle);
00415                     return false;
00416                 }
00417             }
00418         }
00419 
00420         BUCKET_CONSISTENCY(routingAdd: node is in bucket);
00421         return true;
00422     }
00423 
00424     /* check if node can be added to the sibling list -----------------------*/
00425     if (siblingTable->isAddable(handle) ) {
00426         if (secureMaintenance && !authenticated) {
00427             if (!maintenanceLookup || (isAlive && (rtt == MAXTIME))) {
00428                 // received a FindNodeCall or PingCall from a potential sibling
00429                 // or new nodes from a FindNodeResponse app lookup
00430                 pingNode(handle);
00431             } else if (newMaintenance) {
00432                 // new node from sibling table refresh
00433                 //sendSiblingFindNodeCall(handle);
00434                 pingNode(handle);
00435             }
00436             return false;
00437         }
00438 
00439         // ping new siblings
00440         if (pingNewSiblings && !isAlive) {
00441             pingNode(handle);
00442         }
00443 
00444         // R/Kademlia
00445         else if (needsRtt) {
00446             // old version: pingNode(), now:
00447             Prox prox =
00448                     neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
00449                                            this, NULL);
00450             if (prox != Prox::PROX_SELF &&
00451                 prox != Prox::PROX_UNKNOWN &&
00452                 prox != Prox::PROX_TIMEOUT) {
00453                 kadHandle.setProx(prox);
00454             } else if (prox == Prox::PROX_TIMEOUT) {
00455                 // do not put handle into sibling table
00456                 return false;
00457             }
00458         }
00459 
00460         bool finished = false;
00461         int siblingPos = -1;
00462 
00463         // check if sibling list is full so a handle is preemted from the list
00464         if (siblingTable->isFull()) {
00465             // get handle thats about to be preempted
00466             KademliaBucketEntry oldHandle = siblingTable->back();
00467             assert(oldHandle.getKey() != kadHandle.getKey());
00468 
00469             // add handle to the sibling list
00470             siblingPos = siblingTable->add(kadHandle);
00471 
00472             // change, so that the preempted handle is added to a bucket
00473             kadHandle = oldHandle;
00474 
00475             // call update() for removed sibling
00476             if (!secureMaintenance) {
00477                 deleteOverlayNeighborArrow(oldHandle);
00478                 callUpdate(oldHandle, false);
00479             }
00480 
00481             // return always true, since the handle has been added
00482             result = true;
00483         } else {
00484             // simply add the handle and stop
00485             siblingPos = siblingTable->add(kadHandle);
00486 
00487             // don't need to add kadHandle also to regular buckets
00488             finished = true;
00489         }
00490         assert(siblingPos > -1);
00491 
00492         updateTooltip();
00493 
00494         // call update() for new sibling
00495         showOverlayNeighborArrow(handle, false,
00496                                  "m=m,50,100,50,100;ls=green,1");
00497         callUpdate(handle, true);
00498 
00499         if (finished) {
00500             BUCKET_CONSISTENCY(routingAdd: node is now sibling);
00501             return true;
00502         }
00503     }
00504 
00505     /* add node to the appropriate bucket, if not full ---------------------*/
00506     bucket = routingBucket(kadHandle.getKey(), true);
00507     if (!bucket->isFull()) {
00508         if (secureMaintenance && !authenticated) {
00509             if ((isAlive && (rtt == MAXTIME))) {
00510                 // received a FindNodeCall or PingCall from a potential new bucket entry
00511                 // or new nodes from a FindNodeReponse app lookup
00512                 // optimization: don't send a ping for nodes from FindNodeResponse for app lookups
00513                 pingNode(kadHandle);
00514             }
00515             return false;
00516         }
00517 
00518         EV << "[Kademlia::routingAdd()]\n"
00519            << "    Adding new node " << kadHandle
00520            << " to bucket " << routingBucketIndex(kadHandle.getKey())
00521            << endl;
00522 
00523         // PNS
00524         if (needsRtt || proximityNeighborSelection) {
00525              //pingNode(handle, -1, 0, NULL, NULL, NULL, -1, UDP_TRANSPORT, false);
00526              Prox prox =
00527                  neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
00528                                         this, NULL);
00529              if (prox != Prox::PROX_SELF &&
00530                  prox != Prox::PROX_UNKNOWN &&
00531                  prox != Prox::PROX_TIMEOUT) {
00532                  //routingAdd(handle, true, prox.proximity);//ctrlInfo->getSrcRoute() //TODO
00533                  kadHandle.setProx(prox);
00534              }
00535          }
00536 
00537         bucket->push_back(kadHandle);
00538         result = true;
00539     } else if (isAlive) {
00540         //PNS node replacement
00541         if (proximityNeighborSelection &&
00542             kadHandle.getProx() != Prox::PROX_UNKNOWN) {
00543             KademliaBucket::iterator kickHim, it;
00544             kickHim = it = bucket->begin();
00545             ++it;
00546             while (it != bucket->end()) {
00547                 if (it->getRtt() > kickHim->getRtt()) {
00548                     kickHim = it;
00549                 }
00550                 ++it;
00551             }
00552             if (kickHim->getRtt() > kadHandle.getRtt()) {
00553                 KademliaBucketEntry temp = *kickHim;
00554                 bucket->erase(kickHim);
00555                 bucket->push_back(kadHandle);
00556                 kadHandle = temp;
00557             }
00558         }
00559 
00560         if (enableReplacementCache && (!secureMaintenance || authenticated)) {
00561             bucket->replacementCache.push_front(kadHandle);
00562             if (bucket->replacementCache.size() > replacementCandidates) {
00563                 bucket->replacementCache.pop_back();
00564             }
00565 
00566             if (replacementCachePing) {
00567                 KademliaBucket::iterator it = bucket->begin();
00568                 while (it != bucket->end() && (it->getPingSent() == true)) {
00569                     it++;
00570                 }
00571                 if (it != bucket->end()) {
00572                     pingNode(*it);
00573                     it->setPingSent(true);
00574                 }
00575             }
00576         }
00577     }
00578 
00579     // PNS
00580     else if (proximityNeighborSelection) {
00581         neighborCache->getProx(handle, NEIGHBORCACHE_QUERY, -1, this, NULL);
00582         //pingNode(handle);
00583     }
00584 
00585     BUCKET_CONSISTENCY(routingAdd: end);
00586     return result;
00587 }
00588 
00589 bool Kademlia::routingTimeout(const OverlayKey& key, bool immediately)
00590 {
00591     BUCKET_CONSISTENCY(routingTimeout: start);
00592     // key unspecified? yes -> ignore
00593     if (key.isUnspecified())
00594         return false;
00595 
00596     // bucket index
00597     KademliaBucket::iterator i;
00598 
00599     /* check if the node is one of the siblings -----------------------------*/
00600     if ((i = siblingTable->findIterator(key)) != siblingTable->end()) {
00601 
00602         i->incStaleCount();
00603         i->setPingSent(false);
00604 
00605         if (i->getStaleCount() > maxStaleCount || immediately) {
00606             // remove from sibling table
00607             NodeHandle oldSibling = *i;
00608             siblingTable->erase(i);
00609 
00610             // lost last sibling?
00611             if (siblingTable->size() == 0) {
00612                 join();
00613                 return true;
00614             }
00615 
00616             BUCKET_CONSISTENCY(routingTimeout: is sibling);
00617 
00618             // try to refill with new closest contact
00619             refillSiblingTable();
00620 
00621             // call update() for removed sibling
00622             deleteOverlayNeighborArrow(oldSibling);
00623             callUpdate(oldSibling, false);
00624 
00625             updateTooltip();
00626 
00627             return true;
00628         }
00629     }
00630 
00631     /* check if node is already in a bucket ---------------------------------*/
00632     KademliaBucket* bucket = routingBucket(key, false);
00633     if (bucket != NULL && (i = bucket->findIterator(key) ) != bucket->end() ) {
00634 
00635         i->incStaleCount();
00636         i->setPingSent(false);
00637 
00638         if (i->getStaleCount() > maxStaleCount || immediately) {
00639             // remove from routing table
00640             bucket->erase(i);
00641 
00642             if (enableReplacementCache) {
00643                 if (bucket->replacementCache.size()) {
00644                     routingAdd(bucket->replacementCache.front(), true,
00645                                bucket->replacementCache.front().getRtt());
00646                     bucket->replacementCache.pop_front();
00647                     nodesReplaced++;
00648                 }
00649             }
00650         }
00651 
00652         BUCKET_CONSISTENCY(routingTimeout: is in bucket);
00653         return true;
00654     }
00655     BUCKET_CONSISTENCY(routingTimeout: end);
00656     return false;
00657 }
00658 
00659 void Kademlia::refillSiblingTable()
00660 {
00661     if (siblingTable->size() == 0 ||
00662         siblingTable->isFull())
00663         return;
00664 
00665     int index = routingBucketIndex(siblingTable->back().getKey()) - 1;
00666     assert(index > 0);
00667 
00668     while ((routingTable[index] == NULL ||
00669             routingTable[index]->empty()) &&
00670             index < (int)(OverlayKey::getLength() - 1)) {
00671         index++;
00672     }
00673     if (index < (int)OverlayKey::getLength() &&
00674             routingTable[index] != NULL && routingTable[index]->size()) {
00675 
00676         KademliaBucket sortedBucket(k, comparator);
00677         for (uint32_t i = 0; i < routingTable[index]->size(); ++i) {
00678             sortedBucket.add(routingTable[index]->at(i));
00679         }
00680 
00681         siblingTable->add(sortedBucket.front());
00682 
00683         // call update() for new sibling
00684         if (!secureMaintenance) {
00685             showOverlayNeighborArrow(sortedBucket.front(), false,
00686                                      "m=m,50,100,50,100;ls=green,1");
00687             callUpdate(sortedBucket.front(), true);
00688         }
00689 
00690         // remove node from bucket
00691         routingTable[index]->erase(routingTable[index]->
00692               findIterator(sortedBucket.front().getKey()));
00693         assert(siblingTable->isFull());
00694         BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable());
00695     }
00696 }
00697 
00698 void Kademlia::setBucketUsage(const OverlayKey& key)
00699 {
00700     KademliaBucket* bucket = routingBucket(key, true);
00701 
00702     if (bucket) {
00703         bucket->setLastUsage(simTime());
00704     }
00705 
00706     if ((siblingTable->size() < (uint32_t)getMaxNumSiblings())
00707         || ((siblingTable->at(getMaxNumSiblings() - 1).getKey() ^ thisNode.getKey())
00708                 >= (key ^ thisNode.getKey()))) {
00709         siblingTable->setLastUsage(simTime());
00710     }
00711 
00712 }
00713 
00714 bool Kademlia::isSiblingFor(const NodeHandle& node, const OverlayKey& key,
00715                             int numSiblings, bool* err)
00716 {
00717     if (key.isUnspecified())
00718         error("Kademlia::isSiblingFor(): key is unspecified!");
00719 
00720     if (state != READY) {
00721         EV << "[Kademlia::isSiblingFor()] @ "
00722            << thisNode.getIp()
00723            << " (" << thisNode.getKey().toString(16) << ")]\n"
00724            << "    state != READY"
00725            << endl;
00726         *err = true;
00727         return false;
00728     }
00729 
00730     if (numSiblings > getMaxNumSiblings()) {
00731         opp_error("Kademlia::isSiblingFor(): numSiblings too big!");
00732     }
00733 
00734     // set default number of siblings to consider
00735     if (numSiblings == -1) {
00736         numSiblings = getMaxNumSiblings();
00737     }
00738 
00739     if (numSiblings == 0) {
00740         *err = false;
00741         return (node.getKey() == key);
00742     }
00743 
00744     if (siblingTable->size() < (uint)numSiblings) {
00745         *err = false;
00746         return true;
00747     }
00748 
00749     if (siblingTable->isFull() &&
00750         ((thisNode.getKey() ^ key) >
00751          (thisNode.getKey() ^ siblingTable->back().getKey()))) {
00752         EV << "[Kademlia::isSiblingFor()] @ "
00753            << thisNode.getIp()
00754            << " (" << thisNode.getKey().toString(16) << ")]\n"
00755            << "    Not sure if I am sibling for " << key << " !\n"
00756            << "    (" << key << " is not closer to me than "
00757            << siblingTable->back().getKey() << ")"
00758            << endl;
00759         *err = true;
00760         return false;
00761     }
00762 
00763     KeyDistanceComparator<KeyXorMetric>* comp =
00764         new KeyDistanceComparator<KeyXorMetric>(key);
00765 
00766     // create result vector
00767     NodeVector* result = new NodeVector(numSiblings, comp);
00768 
00769     for (KademliaBucket::iterator i=siblingTable->begin();
00770          i != siblingTable->end(); i++) {
00771         result->add( *i);
00772     }
00773 
00774     // add local node
00775     result->add(thisNode);
00776 
00777     *err = false;
00778     delete comp;
00779 
00780     if (result->contains(node.getKey())) {
00781         delete result;
00782         return true;
00783     } else {
00784         delete result;
00785         assert(!(numSiblings == 1 && key == node.getKey()));
00786         return false;
00787     }
00788 }
00789 
00790 void Kademlia::handleNodeGracefulLeaveNotification()
00791 {
00792     // send failed node call to all siblings
00793     FailedNodeCall* call = new FailedNodeCall();
00794     call->setFailedNode(getThisNode());
00795     call->setBitLength(FAILEDNODECALL_L(call));
00796     for (KademliaBucket::iterator i = siblingTable->begin();
00797          i != siblingTable->end(); i++) {
00798         countFailedNodeCall(call);
00799         sendUdpRpcCall(*i, call->dup());
00800     }
00801 
00802     delete call;
00803 }
00804 
00805 bool Kademlia::handleFailedNode(const TransportAddress& failed)
00806 {
00807     assert(!failed.isUnspecified());
00808 
00809     KademliaBucket::iterator i;
00810     // check sibling table
00811     for (i = siblingTable->begin(); i != siblingTable->end(); ++i) {
00812         if (failed == *i) break;
00813     }
00814 
00815     if (i != siblingTable->end()) {
00816         // remove from sibling table
00817         NodeHandle oldSibling = *i;
00818         siblingTable->erase(i);
00819 
00820         // call update() for removed sibling
00821         deleteOverlayNeighborArrow(oldSibling);
00822         callUpdate(oldSibling, false);
00823 
00824         updateTooltip();
00825 
00826         // try to refill with new closest contact
00827         refillSiblingTable();
00828     } else {
00829         // check buckets
00830         uint32_t m;
00831         for (m = 0; m < routingTable.size(); ++m) {
00832             if (routingTable[m] != NULL) {
00833                 for (i = routingTable[m]->begin(); i != routingTable[m]->end();
00834                      ++i) {
00835                     if (failed == *i) {
00836                         // remove from routing table
00837                         routingTable[m]->erase(i);
00838                         return (siblingTable->size() != 0);
00839                     }
00840                 }
00841             }
00842         }
00843     }
00844     return (siblingTable->size() != 0);
00845 }
00846 
00847 // R/Kademlia
00848 bool Kademlia::recursiveRoutingHook(const TransportAddress& dest,
00849                                     BaseRouteMessage* msg)
00850 {
00851     if (msg->getSrcNode() != thisNode) {
00852         if (!msg->getDestKey().isUnspecified()) {
00853             routingAdd(msg->getSrcNode(), true);
00854 
00855             if (altRecMode && dest != thisNode) return true;
00856 
00857             NodeVector* nextHops = findNode(msg->getDestKey(), /*recursiveLookupConfig.redundantNodes*/ k, s, msg);
00858             KademliaRoutingInfoMessage* kadRoutingInfoMsg =
00859                 new KademliaRoutingInfoMessage();
00860 
00861             kadRoutingInfoMsg->setSrcNode(thisNode);
00862             kadRoutingInfoMsg->setDestKey(msg->getDestKey());
00863             kadRoutingInfoMsg->setNextHopsArraySize(nextHops->size());
00864             kadRoutingInfoMsg->setName("KadRoutingInfoMsg");
00865             for (uint32_t i = 0; i < nextHops->size(); i++) {
00866                 kadRoutingInfoMsg->setNextHops(i, (*nextHops)[i]);
00867                 if (thisNode == kadRoutingInfoMsg->getNextHops(i)) {
00868                     kadRoutingInfoMsg->getNextHops(i).setIsAlive(true);
00869                 }
00870             }
00871             kadRoutingInfoMsg->setBitLength(KADEMLIAROUTINGINFO_L(kadRoutingInfoMsg));
00872 
00873             delete nextHops;
00874 
00875             if (!altRecMode) {
00876                 sendMessageToUDP(msg->getSrcNode(), kadRoutingInfoMsg);
00877             } else {
00878                 // alternative maintenance mode
00879                 std::vector<TransportAddress> sourceRoute;
00880                 for (int i = msg->getVisitedHopsArraySize() - 1/*2*/; i >= 0; i--) {
00881                     //TODO remove loops
00882                     sourceRoute.push_back(msg->getVisitedHops(i));
00883                 }
00884                 //sourceRoute.push_back(msg->getSrcNode());
00885                 sendToKey(OverlayKey::UNSPECIFIED_KEY, kadRoutingInfoMsg, 0,
00886                           sourceRoute, NO_OVERLAY_ROUTING);
00887             }
00888             //TODO should be sent after baseroutemsg
00889         } else if (altRecMode &&
00890                    dynamic_cast<KademliaRoutingInfoMessage*>(msg->
00891                            getEncapsulatedPacket())) {
00892             // alternative mode: infoMsg on its way back
00893             KademliaRoutingInfoMessage* infoMsg =
00894                 static_cast<KademliaRoutingInfoMessage*>(msg->decapsulate());
00895             NodeVector* nextHops = findNode(infoMsg->getDestKey(), k, s, msg);
00896 
00897             // merge vectors
00898             KeyDistanceComparator<KeyXorMetric> comp(infoMsg->getDestKey());
00899             MarkedNodeVector temp(UINT16_MAX, &comp);
00900 
00901             for (uint32_t i = 0; i < nextHops->size(); i++) {
00902                 temp.push_back((*nextHops)[i]);
00903             }
00904             delete nextHops;
00905 
00906             for (uint32_t i = 0; i < infoMsg->getNextHopsArraySize(); i++) {
00907                 routingAdd(infoMsg->getNextHops(i),
00908                            infoMsg->getNextHops(i).getIsAlive());
00909                 temp.add(infoMsg->getNextHops(i));
00910             }
00911 
00912             infoMsg->setNextHopsArraySize(temp.size());
00913             for (uint32_t i = 0; i < temp.size(); ++i) {
00914                 infoMsg->setNextHops(i, temp[i]);
00915                 if (thisNode == infoMsg->getNextHops(i)) {
00916                     infoMsg->getNextHops(i).setIsAlive(true);
00917                 }
00918             }
00919             infoMsg->setBitLength(KADEMLIAROUTINGINFO_L(infoMsg));
00920 
00921             msg->encapsulate(infoMsg);
00922         }
00923     }
00924     return true;
00925 }
00926 
00927 
00928 NodeVector* Kademlia::findNode(const OverlayKey& key, int numRedundantNodes,
00929                                int numSiblings, BaseOverlayMessage* msg)
00930 {
00931     if (numSiblings > getMaxNumSiblings()) {
00932         opp_error("(Kademlia::findNode()) numRedundantNodes or numSiblings "
00933                   "too big!");
00934     }
00935 
00936 #if 0
00937     if (numRedundantNodes < 2) {
00938         throw cRuntimeError("Kademlia::findNode(): For Kademlia "
00939                                 "redundantNodes must be at least 2 "
00940                                 "and lookupMerge should be true!");
00941     }
00942 #endif
00943 
00944     // create temporary comparator
00945     KeyDistanceComparator<KeyXorMetric>* comp =
00946         new KeyDistanceComparator<KeyXorMetric>( key );
00947 
00948     // select result set size
00949     bool err;
00950     int resultSize;
00951 
00952     if (numSiblings < 0) {
00953         // exhaustive iterative doesn't care about siblings
00954         resultSize = numRedundantNodes;
00955     } else {
00956         resultSize = isSiblingFor(thisNode, key, numSiblings, &err) ?
00957                 (numSiblings ? numSiblings : 1) : numRedundantNodes;
00958     }
00959     assert(numSiblings || numRedundantNodes);
00960 
00961     NodeVector* result = new NodeVector(resultSize, comp);
00962 
00963     if (siblingTable->isEmpty()) {
00964         result->add(thisNode);
00965         delete comp;
00966         return result;
00967     }
00968 
00969     // R/Kademlia: in recursive mode just speed up route messages //TODO iterative PR
00970     bool returnProxNodes = false;
00971     if (proximityRouting) {
00972         if (msg &&
00973             (!dynamic_cast<FindNodeCall*>(msg->getEncapsulatedPacket()) &&
00974              !dynamic_cast<FindNodeCall*>(msg))) {
00975             returnProxNodes = true;
00976         }
00977     }
00978 
00979     ProxNodeVector* resultProx = NULL;
00980     KademliaPRComparator* compProx = NULL;
00981     if (returnProxNodes) {
00982         compProx = new KademliaPRComparator(key);
00983         resultProx = new ProxNodeVector(resultSize, NULL, NULL, compProx, 0, resultSize);
00984     }
00985 
00986     // add items from buckets
00987     int index;
00988     int mainIndex = routingBucketIndex(key);
00989     int startIndex = routingBucketIndex(key, true);
00990     int endIndex = routingBucketIndex(siblingTable->back().getKey());
00991 
00992     // add nodes from best fitting bucket
00993     if (mainIndex != -1) {
00994         KademliaBucket* bucket = routingTable[mainIndex];
00995         if (bucket != NULL && bucket->size()) {
00996             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00997                 result->add(*i);
00998                 if (returnProxNodes)
00999                     resultProx->add(*i);
01000                 //EV << "Kademlia::findNode(): Adding "
01001                 //   << *i << " from bucket " << mainIndex << endl;
01002             }
01003         }
01004     }
01005 
01006     // add most fitting buckets
01007     if (startIndex >= endIndex || !result->isFull()) {
01008         for (index = startIndex; index >= endIndex; --index) {
01009             // add bucket to result vector
01010             if (index == mainIndex) continue;
01011             KademliaBucket* bucket = routingTable[index];
01012             if (bucket != NULL && bucket->size()) {
01013                 for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
01014                     result->add(*i);
01015                     if (returnProxNodes)
01016                         resultProx->add(*i);//std::make_pair(*i, i->getRtt()));
01017                     //EV << "Kademlia::routingGetClosestNodes(): Adding "
01018                     //   << *i << " from bucket " << index << endl;
01019                 }
01020             }
01021         }
01022 
01023         // add nodes from sibling table
01024         for (KademliaBucket::iterator i = siblingTable->begin();
01025              i != siblingTable->end(); i++) {
01026             result->add(*i);
01027             if (returnProxNodes)
01028                 resultProx->add(*i);
01029         }
01030         // add local node
01031         result->add(thisNode);
01032         if (returnProxNodes) {
01033             KademliaBucketEntry temp = thisNode;
01034             if (!result->size() || (*result)[0] == thisNode) {
01035                 temp.setProx(Prox::PROX_SELF);
01036                 resultProx->add(temp);
01037             } else {
01038                 temp.setProx(Prox::PROX_UNKNOWN);
01039                 resultProx->add(temp);
01040             }
01041         }
01042     }
01043 
01044     // add more distant buckets
01045     for (index = mainIndex + 1; !result->isFull() && index < numBuckets;
01046          ++index) {
01047         // add bucket to result vector
01048         KademliaBucket* bucket = routingTable[index];
01049         if (bucket != NULL && bucket->size()) {
01050             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
01051                 result->add(*i);
01052                 if (returnProxNodes)
01053                     resultProx->add(*i);
01054                 //EV << "[Kademlia::routingGetClosestNodes()]\n"
01055                 //   << "    Adding " << *i << " from bucket " << index
01056                 //   << endl;
01057             }
01058         }
01059     }
01060 
01061     if (returnProxNodes) {
01062         result->clear();
01063         for (uint32_t i = 0; i < resultProx->size(); ++i) {
01064             result->push_back((*resultProx)[i]/*.first*/);
01065         }
01066         delete compProx;
01067         delete resultProx;
01068     }
01069 
01070     delete comp;
01071 
01072     return result;
01073 }
01074 
01075 //-----------------------------------------------------------------------------
01076 
01077 
01078 void Kademlia::handleTimerEvent(cMessage* msg)
01079 {
01080     if (msg == bucketRefreshTimer) {
01081         handleBucketRefreshTimerExpired();
01082     } else if (msg == siblingPingTimer) {
01083         if (siblingPingInterval == 0) {
01084             return;
01085         }
01086 
01087         for (KademliaBucket::iterator i = siblingTable->begin();
01088              i != siblingTable->end(); i++) {
01089             pingNode(*i);
01090         }
01091         scheduleAt(simTime() + siblingPingInterval, msg);
01092     }
01093 }
01094 
01095 // R/Kademlia
01096 void Kademlia::handleUDPMessage(BaseOverlayMessage* msg)
01097 {
01098     // only used for recursive Kademlia
01099     OverlayCtrlInfo* ctrlInfo =
01100             check_and_cast<OverlayCtrlInfo*>(msg->removeControlInfo());
01101     KademliaRoutingInfoMessage* kadRoutingInfoMsg =
01102             check_and_cast<KademliaRoutingInfoMessage*>(msg);
01103 
01104     routingAdd(kadRoutingInfoMsg->getSrcNode(), true);
01105 
01106     for (uint32_t i = 0; i < kadRoutingInfoMsg->getNextHopsArraySize(); i++) {
01107         routingAdd(kadRoutingInfoMsg->getNextHops(i),
01108                    kadRoutingInfoMsg->getNextHops(i).getIsAlive());
01109     }
01110 
01111     delete ctrlInfo;
01112     delete msg;
01113 }
01114 
01115 //In Kademlia this method is used to maintain the routing table.
01116 bool Kademlia::handleRpcCall(BaseCallMessage* msg)
01117 {
01118     bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
01119     RPC_SWITCH_START(msg)
01120     RPC_ON_CALL(Ping) {
01121         // add active node
01122         OverlayCtrlInfo* ctrlInfo =
01123             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
01124         routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
01125         break;
01126     }
01127     RPC_ON_CALL(FindNode)
01128     {
01129         // add active node
01130         OverlayCtrlInfo* ctrlInfo =
01131             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
01132         routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
01133         break;
01134     }
01135     RPC_SWITCH_END()
01136     return false;
01137 }
01138 
01139 //In Kademlia this method is used to maintain the routing table.
01140 void Kademlia::handleRpcResponse(BaseResponseMessage* msg,
01141                                  cPolymorphic* context, int rpcId,
01142                                  simtime_t rtt)
01143 {
01144     bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
01145     OverlayCtrlInfo* ctrlInfo =
01146         dynamic_cast<OverlayCtrlInfo*>(msg->getControlInfo());
01147     NodeHandle srcRoute = (ctrlInfo ? ctrlInfo->getSrcRoute()
01148                                     : msg->getSrcNode());
01149 
01150     RPC_SWITCH_START(msg)
01151         RPC_ON_RESPONSE(Ping) {
01152             if (state == INIT) {
01153                 // schedule bucket refresh timer
01154                 cancelEvent(bucketRefreshTimer);
01155                 scheduleAt(simTime(), bucketRefreshTimer);
01156                 cancelEvent(siblingPingTimer);
01157                 scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
01158                 state = JOIN;
01159             }
01160         }
01161         RPC_ON_RESPONSE(FindNode)
01162         {
01163             if (state == INIT) {
01164                 state = JOIN;
01165 
01166                 // bootstrap node is trustworthy: add all nodes immediately
01167                 routingAdd(srcRoute, true, rtt, maintenanceLookup);
01168                 for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
01169                     routingAdd(_FindNodeResponse->getClosestNodes(i), true,
01170                                MAXTIME-1, maintenanceLookup);
01171 
01172                 if (newMaintenance) {
01173                     createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
01174                                        new KademliaLookupListener(this));
01175                 } else {
01176                     // schedule bucket refresh timer
01177                     cancelEvent(bucketRefreshTimer);
01178                     scheduleAt(simTime(), bucketRefreshTimer);
01179                     cancelEvent(siblingPingTimer);
01180                     scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
01181                 }
01182 
01183                 break;
01184             }
01185 
01186             // add active node
01187             if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
01188                 defaultRoutingType == FULL_RECURSIVE_ROUTING ||
01189                 defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
01190                 rtt = MAXTIME;
01191             }
01192             setBucketUsage(srcRoute.getKey());
01193 
01194             // add inactive nodes
01195             for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
01196                 routingAdd(_FindNodeResponse->getClosestNodes(i), false,
01197                            MAXTIME, maintenanceLookup);
01198             break;
01199         }
01200     RPC_SWITCH_END()
01201 
01202     // add node that responded
01203     routingAdd(srcRoute, true, rtt, maintenanceLookup);
01204 }
01205 
01206 // In Kademlia this method is used to maintain the routing table.
01207 void Kademlia::handleRpcTimeout(BaseCallMessage* msg,
01208                                 const TransportAddress& dest,
01209                                 cPolymorphic* context, int rpcId,
01210                                 const OverlayKey& destKey)
01211 {
01212     if (dest.isUnspecified()) return;
01213     try {
01214         RPC_SWITCH_START(msg)
01215         RPC_ON_CALL(Ping) {
01216             if (state == INIT) {
01217                 joinOverlay();
01218                 return;
01219             }
01220 
01221             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
01222             routingTimeout(handle.getKey());
01223             break;
01224         }
01225         RPC_ON_CALL(FindNode) {
01226             if (state == INIT) {
01227                 joinOverlay();
01228                 return;
01229             }
01230 
01231             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
01232             routingTimeout(handle.getKey());
01233             setBucketUsage(handle.getKey());
01234             break;
01235         }
01236         RPC_SWITCH_END()
01237     } catch (...) {
01238         EV << "[Kademlia:handleRpcTimout() @ " << thisNode.getIp()
01239            << " (" << thisNode.getKey().toString(16) << ")]\n"
01240            << "    ERROR: RPC timeout without key ("
01241            << msg << " -> " << dest << ")" << endl;
01242         return;
01243     }
01244 }
01245 
01246 // R/Kademlia
01247 void Kademlia::proxCallback(const TransportAddress& node, int rpcId,
01248                             cPolymorphic *contextPointer, Prox prox)
01249 {
01250     Enter_Method_Silent();
01251 
01252     if (prox != Prox::PROX_TIMEOUT) {
01253         routingAdd((const NodeHandle&)node, true, prox.proximity);
01254     } else {
01255         routingTimeout(((const NodeHandle&)node).getKey());
01256     }
01257 }
01258 
01259 void Kademlia::lookupFinished(bool isValid)
01260 {
01261     if (state == JOIN) {
01262         cancelEvent(bucketRefreshTimer);
01263 
01264         if (siblingTable->size() == 0) {
01265             // initial lookup failed - get new bootstrap node
01266             joinOverlay();
01267             return;
01268         }
01269 
01270         scheduleAt(simTime(), bucketRefreshTimer);
01271 
01272         if (!newMaintenance) {
01273             state = READY;
01274             setOverlayReady(true);
01275         }
01276     }
01277 }
01278 
01279 // handle a expired bucket refresh timer
01280 void Kademlia::handleBucketRefreshTimerExpired()
01281 {
01282     // refresh buckets
01283     if (state != READY || (((simTime() - siblingTable->getLastUsage()) >
01284                             minSiblingTableRefreshInterval))) {
01285         // R/Kademlia
01286         if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
01287             defaultRoutingType == FULL_RECURSIVE_ROUTING ||
01288             defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
01289             //TODO real exhaustive-recursive lookup
01290             createLookup()->lookup(getThisNode().getKey() + OverlayKey::ONE,
01291                                    0, hopCountMax, 0,
01292                                    new KademliaLookupListener(this));
01293         } else if (exhaustiveRefresh) {
01294             //TODO config shit
01295             int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
01296             iterativeLookupConfig.redundantNodes = siblingRefreshNodes;
01297             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
01298                  getThisNode().getKey(), siblingRefreshNodes,
01299                  hopCountMax, 0, new KademliaLookupListener(this));
01300             iterativeLookupConfig.redundantNodes = baseRedundantNodes;
01301         } else if (newMaintenance) {
01302             //for (KademliaBucket::iterator i = siblingTable->begin();
01303             //     i != siblingTable->end(); i++) {
01304 
01305             //    sendSiblingFindNodeCall(*i);
01306             //}
01307             if (siblingTable->size()) {
01308                 sendSiblingFindNodeCall(siblingTable->at(intuniform(0,siblingTable->size()-1)));
01309             }
01310             state = READY;
01311             setOverlayReady(true);
01312         } else {
01313             createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
01314                                    new KademliaLookupListener(this));
01315         }
01316         siblingTable->setLastUsage(simTime());
01317         ++siblingTableRefreshCount;
01318     }
01319 
01320     if (state == READY) {
01321         if (siblingTable->size()) {
01322             // get bit index of most significant digit that differs
01323             // from our next sibling's key to prevent us from refreshing
01324             // buckets, which can't contain any nodes
01325             int32_t diff = OverlayKey::getLength() - b*(getThisNode().getKey().
01326                 sharedPrefixLength(siblingTable->front().getKey(), b) + 1);
01327             int bucketsRefreshedPerTask = 0;
01328             for (int32_t i = OverlayKey::getLength() - b; i >= diff; i -=b ) {
01329                 for (int32_t d=0; d < ((1 << b) - 1); d++) {
01330                     int32_t index = (i / b) * ((1 << b) - 1) + d;
01331                     if (index < 0) continue;
01332                     if ((routingTable[index] == NULL) ||
01333                         ((simTime() - routingTable[index]->getLastUsage()) >
01334                         minBucketRefreshInterval)) {
01335 
01336                         OverlayKey refreshKey =
01337                             getThisNode().getKey() ^ (OverlayKey(d+1) << i);
01338 
01339                         // R/Kademlia
01340                         if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
01341                             defaultRoutingType == FULL_RECURSIVE_ROUTING ||
01342                             defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
01343                             //TODO real exhaustive-recursive lookup
01344                             createLookup()->lookup(refreshKey, 0,
01345                                                    hopCountMax, 0,
01346                                                    new KademliaLookupListener(this));
01347                         } else if (exhaustiveRefresh) {
01348                             //TODO config shit
01349                             int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
01350                             iterativeLookupConfig.redundantNodes = bucketRefreshNodes;
01351                             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
01352                                 refreshKey, bucketRefreshNodes, hopCountMax,
01353                                 0, new KademliaLookupListener(this));
01354                             iterativeLookupConfig.redundantNodes = baseRedundantNodes;
01355                         } else {
01356                             createLookup()->lookup(refreshKey, s, hopCountMax, 0,
01357                                              new KademliaLookupListener(this));
01358                         }
01359 
01360                         ++bucketsRefreshedPerTask;
01361                         ++bucketRefreshCount;
01362                         setBucketUsage(refreshKey);
01363                     }
01364                 }
01365             }
01366             RECORD_STATS(globalStatistics->recordOutVector(
01367                                    "Kademlia: Buckets Refreshed Per Task",
01368                                    bucketsRefreshedPerTask));
01369         }
01370         // schedule next bucket refresh process
01371         cancelEvent(bucketRefreshTimer);
01372         scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval,
01373                         minBucketRefreshInterval) / 10.0), bucketRefreshTimer);
01374     }
01375 }
01376 
01377 //virtual public: xor metric
01378 OverlayKey Kademlia::distance(const OverlayKey& x,
01379                               const OverlayKey& y,
01380                               bool useAlternative) const
01381 {
01382     if (!useAlternative) return x^y; // KeyXorMetric().distance(x, y);
01383     return KeyPrefixMetric().distance(x, y);
01384 }
01385 
01386 void Kademlia::updateTooltip()
01387 {
01388     if (ev.isGUI()) {
01389         std::stringstream ttString;
01390 
01391         // show our nodeId in a tooltip
01392         ttString << "This: " << thisNode << endl << "Siblings: "
01393                  << siblingTable->size();
01394 
01395         getParentModule()->getParentModule()->getDisplayString().
01396         setTagArg("tt", 0, ttString.str().c_str());
01397         getParentModule()->getDisplayString().
01398         setTagArg("tt", 0, ttString.str().c_str());
01399         getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
01400     }
01401 }
01402