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     k = par("k");
00116     b = par("b");
00117     s = par("s");
00118 
00119     siblingRefreshNodes = par("siblingRefreshNodes");
00120 
00121     if (siblingRefreshNodes <= 0) {
00122         siblingRefreshNodes = 5 * s;
00123     }
00124 
00125     bucketRefreshNodes = par("bucketRefreshNodes");
00126 
00127     if (bucketRefreshNodes <= 0) {
00128         bucketRefreshNodes = iterativeLookupConfig.redundantNodes;
00129     }
00130 
00131     // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b )
00132     numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b);
00133 
00134     // init routing and sibling table
00135     siblingTable = new KademliaBucket(s * 5, NULL);
00136 
00137     // initialize pointers
00138     routingTable.assign(numBuckets, (KademliaBucket*)NULL);
00139 
00140     WATCH_VECTOR(*siblingTable);
00141     WATCH_VECTOR(routingTable);
00142 
00143     // self-message
00144     bucketRefreshTimer = new cMessage("bucketRefreshTimer");
00145     siblingPingTimer = new cMessage("siblingPingTimer");
00146 
00147     // statistics
00148     bucketRefreshCount = 0;
00149     siblingTableRefreshCount = 0;
00150     nodesReplaced = 0;
00151 
00152     comparator = NULL;
00153 }
00154 
00155 Kademlia::Kademlia()
00156 {
00157     siblingTable = NULL;
00158     comparator = NULL;
00159     bucketRefreshTimer = NULL;
00160     siblingPingTimer = NULL;
00161 }
00162 
00163 Kademlia::~Kademlia()
00164 {
00165     routingDeinit();
00166 
00167     delete siblingTable;
00168     delete comparator;
00169     cancelAndDelete(bucketRefreshTimer);
00170     cancelAndDelete(siblingPingTimer);
00171 }
00172 
00173 void Kademlia::finishOverlay()
00174 {
00175     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00176     if (time < GlobalStatistics::MIN_MEASURED) return;
00177 
00178     globalStatistics->addStdDev("Kademlia: Nodes replaced in buckets/s",
00179                                 nodesReplaced / time);
00180     globalStatistics->addStdDev("Kademlia: Bucket Refreshes/s",
00181                                 bucketRefreshCount / time);
00182     globalStatistics->addStdDev("Kademlia: Sibling Table Refreshes/s",
00183                                 siblingTableRefreshCount / time);
00184 }
00185 
00186 void Kademlia::sendSiblingFindNodeCall(const TransportAddress& dest)
00187 {
00188     FindNodeCall* call = new FindNodeCall("FindNodeCall");
00189     call->setExhaustiveIterative(true);
00190     call->setLookupKey(thisNode.getKey());
00191     call->setNumRedundantNodes(siblingRefreshNodes);
00192     call->setNumSiblings(getMaxNumSiblings());
00193     call->setBitLength(FINDNODECALL_L(call));
00194     sendUdpRpcCall(dest, call);
00195 }
00196 
00197 void Kademlia::joinOverlay()
00198 {
00199     // remove current node handle from the bootstrap list
00200     if (!thisNode.getKey().isUnspecified()) {
00201         bootstrapList->removeBootstrapNode(thisNode);
00202     }
00203 
00204     // initialize routing
00205     routingDeinit();
00206     routingInit();
00207 
00208     TransportAddress handle = bootstrapList->getBootstrapNode();
00209 
00210     if (!handle.isUnspecified()) {
00211         if (secureMaintenance) {
00212             sendSiblingFindNodeCall(handle);
00213         } else {
00214             // ping the bootstrap node to start bootstrapping
00215             pingNode(handle);
00216         }
00217     } else {
00218         // we're the only node in the network
00219         state = READY;
00220         setOverlayReady(true);
00221 
00222         // schedule bucket refresh timer
00223         cancelEvent(bucketRefreshTimer);
00224         scheduleAt(simTime(), bucketRefreshTimer);
00225         cancelEvent(siblingPingTimer);
00226         scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
00227     }
00228 }
00229 
00230 //-----------------------------------------------------------------------------
00231 
00232 void Kademlia::routingInit()
00233 {
00234     // set join state
00235     state = INIT;
00236 
00237     setOverlayReady(false);
00238 
00239     // setup comparator
00240     comparator = new KeyDistanceComparator<KeyXorMetric>(thisNode.getKey());
00241 
00242     siblingTable->setComparator(comparator);
00243 
00244     updateTooltip();
00245     BUCKET_CONSISTENCY(routingInit: end);
00246 }
00247 
00248 void Kademlia::routingDeinit()
00249 {
00250     // delete buckets
00251     for (uint32_t i = 0; i < routingTable.size(); i++) {
00252         if (routingTable[i] != NULL) {
00253             delete routingTable[i];
00254             routingTable[i] = NULL;
00255         }
00256     }
00257 
00258     if (siblingTable != NULL) {
00259         siblingTable->clear();
00260     }
00261 
00262     if (comparator != NULL) {
00263         delete comparator;
00264         comparator = NULL;
00265     }
00266 }
00267 
00268 int Kademlia::getMaxNumSiblings()
00269 {
00270     return s;
00271 }
00272 
00273 int Kademlia::getMaxNumRedundantNodes()
00274 {
00275     return k;
00276 }
00277 
00278 int Kademlia::routingBucketIndex(const OverlayKey& key, bool firstOnLayer)
00279 {
00280     // calculate XOR distance
00281     OverlayKey delta = key ^ getThisNode().getKey();
00282 
00283     // find first subinteger that is not zero...
00284     int i;
00285     for (i = key.getLength() - b; i >= 0 && delta.getBitRange(i, b) == 0;
00286          i -= b);
00287 
00288     if (i < 0)
00289         return -1;
00290 
00291     if (!firstOnLayer)
00292         return (i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1);
00293     else
00294         return (i / b) * ((1 << b) - 1) + (pow(2, b) - 2);
00295 }
00296 
00297 KademliaBucket* Kademlia::routingBucket(const OverlayKey& key, bool ensure)
00298 {
00299     // get bucket index
00300     int num = routingBucketIndex(key);
00301     if (num < 0)
00302         return NULL;
00303 
00304     // get bucket and allocate if necessary
00305     KademliaBucket* bucket = routingTable[ num ];
00306     if (bucket == NULL && ensure)
00307         bucket = routingTable[ num ] = new KademliaBucket( k, comparator );
00308 
00309     // return bucket
00310     return bucket;
00311 }
00312 
00313 bool Kademlia::routingAdd(const NodeHandle& handle, bool isAlive,
00314                           simtime_t rtt, bool maintenanceLookup)
00315 {
00316     BUCKET_CONSISTENCY(routingAdd: start);
00317     // never add unspecified node handles
00318     if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey() )
00319         return false;
00320 
00321     // bucket index
00322     KademliaBucket::iterator i;
00323     bool result = false;
00324     bool authenticated = (isAlive && (rtt != MAXTIME));
00325 
00326     // convert node handle
00327     KademliaBucketEntry kadHandle = handle;
00328     kadHandle.setRtt(rtt);
00329     kadHandle.setLastSeen(simTime());
00330 
00331     /* check if node is already a sibling -----------------------------------*/
00332     if ((i = siblingTable->findIterator(handle.getKey()))
00333          != siblingTable->end()) {
00334         // not alive? -> do not change routing information
00335         if (isAlive) {
00336             if (!secureMaintenance || authenticated) {
00337                 if (kadHandle.getRtt() == MAXTIME) {
00338                     kadHandle.setRtt(i->getRtt());
00339                 }
00340                 // refresh sibling
00341                 (*i) = kadHandle;
00342             } else {
00343                 if (maintenanceLookup) {
00344                     return false;
00345                 }
00346 
00347                 if ((i->getAddress() != handle.getAddress()) ||
00348                     (i->getPort() != handle.getPort())) {
00349                     // sibling could have changed transport address
00350                     // ping new address for authentication
00351                     pingNode(handle);
00352                     return false;
00353                 }
00354             }
00355         }
00356         BUCKET_CONSISTENCY(routingAdd: node is sibling);
00357         return true;
00358     }
00359 
00360     /* check if node is already in a bucket ---------------------------------*/
00361     KademliaBucket* bucket = routingBucket(handle.getKey(), false);
00362     if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) )
00363             != bucket->end() ) {
00364         // not alive? -> do not change routing information
00365         if (isAlive) {
00366             if (!secureMaintenance || authenticated) {
00367                 if (kadHandle.getRtt() == MAXTIME) {
00368                     kadHandle.setRtt(i->getRtt());
00369                 }
00370 
00371                 // remove old handle
00372                 bucket->erase(i);
00373                 // re-add to tail
00374                 bucket->push_back(kadHandle);
00375             } else {
00376                 if (maintenanceLookup) {
00377                     return false;
00378                 }
00379 
00380                 if ((i->getAddress() != handle.getAddress()) ||
00381                     (i->getPort() != handle.getPort())) {
00382                     // sibling could have changed transport address
00383                     // ping new address for authentication
00384                     pingNode(handle);
00385                     return false;
00386                 }
00387             }
00388         }
00389 
00390         BUCKET_CONSISTENCY(routingAdd: node is in bucket);
00391         return true;
00392     }
00393 
00394     /* check if node can be added to the sibling list -----------------------*/
00395     if (siblingTable->isAddable(handle) ) {
00396         if (secureMaintenance && !authenticated) {
00397             if (!maintenanceLookup || (isAlive && (rtt == MAXTIME))) {
00398                 // received a FindNodeCall or PingCall from a potential sibling
00399                 // or new nodes from a FindNodeResponse app lookup
00400                 pingNode(handle);
00401             } else if (newMaintenance) {
00402                 // new node from sibling table refresh
00403                 //sendSiblingFindNodeCall(handle);
00404                 pingNode(handle);
00405             }
00406             return false;
00407         }
00408 
00409         bool finished = false;
00410         int siblingPos = -1;
00411 
00412         // check if sibling list is full so a handle is preemted from the list
00413         if (siblingTable->isFull()) {
00414             // get handle thats about to be preempted
00415             KademliaBucketEntry oldHandle = siblingTable->back();
00416             assert(oldHandle.getKey() != kadHandle.getKey());
00417 
00418             // add handle to the sibling list
00419             siblingPos = siblingTable->add(kadHandle);
00420 
00421             // change, so that the preempted handle is added to a bucket
00422             kadHandle = oldHandle;
00423 
00424             // call update() for removed sibling
00425             if (!secureMaintenance) {
00426                 deleteOverlayNeighborArrow(oldHandle);
00427                 callUpdate(oldHandle, false);
00428             }
00429 
00430             // return always true, since the handle has been added
00431             result = true;
00432         } else {
00433             // simply add the handle and stop
00434             siblingPos = siblingTable->add(kadHandle);
00435 
00436             // don't need to add kadHandle also to regular buckets
00437             finished = true;
00438         }
00439         assert(siblingPos > -1);
00440 
00441         // ping new siblings
00442         if ((pingNewSiblings && !isAlive)) {
00443             pingNode(handle);
00444         }
00445 
00446         updateTooltip();
00447 
00448         // call update() for new sibling
00449         showOverlayNeighborArrow(handle, false,
00450                                  "m=m,50,100,50,100;ls=green,1");
00451         callUpdate(handle, true);
00452 
00453         if (finished) {
00454             BUCKET_CONSISTENCY(routingAdd: node is now sibling);
00455             return true;
00456         }
00457     }
00458 
00459     /* add node to the appropriate bucket, if not full ---------------------*/
00460     bucket = routingBucket(kadHandle.getKey(), true);
00461     if (!bucket->isFull()) {
00462 
00463         if (secureMaintenance && !authenticated) {
00464             if ((isAlive && (rtt == MAXTIME))) {
00465                 // received a FindNodeCall or PingCall from a potential new bucket entry
00466                 // or new nodes from a FindNodeReponse app lookup
00467                 // optimization: don't send a ping for nodes from FindNodeResponse for app lookups
00468                 pingNode(kadHandle);
00469             }
00470             return false;
00471         }
00472 
00473         EV << "[Kademlia::routingAdd()]\n"
00474            << "    Adding new node " << kadHandle
00475            << " to bucket " << routingBucketIndex(kadHandle.getKey())
00476            << endl;
00477 
00478         bucket->push_back(kadHandle);
00479         result = true;
00480     } else if (isAlive) {
00481         if (enableReplacementCache && (!secureMaintenance || authenticated)) {
00482             bucket->replacementCache.push_front(kadHandle);
00483             if (bucket->replacementCache.size() > replacementCandidates) {
00484                 bucket->replacementCache.pop_back();
00485             }
00486 
00487             if (replacementCachePing) {
00488                 KademliaBucket::iterator it = bucket->begin();
00489                 while (it != bucket->end() && (it->getPingSent() == true)) {
00490                     it++;
00491                 }
00492                 if (it != bucket->end()) {
00493                     pingNode(*it);
00494                     it->setPingSent(true);
00495                 }
00496             }
00497         }
00498     }
00499 
00500     BUCKET_CONSISTENCY(routingAdd: end);
00501     return result;
00502 }
00503 
00504 bool Kademlia::routingTimeout(const OverlayKey& key, bool immediately)
00505 {
00506     BUCKET_CONSISTENCY(routingTimeout: start);
00507     // key unspecified? yes -> ignore
00508     if (key.isUnspecified())
00509         return false;
00510 
00511     // bucket index
00512     KademliaBucket::iterator i;
00513 
00514     /* check if the node is one of the siblings -----------------------------*/
00515     if ((i = siblingTable->findIterator(key)) != siblingTable->end()) {
00516 
00517         i->incStaleCount();
00518         i->setPingSent(false);
00519 
00520         if (i->getStaleCount() > maxStaleCount || immediately) {
00521             // remove from sibling table
00522             NodeHandle oldSibling = *i;
00523             siblingTable->erase(i);
00524 
00525             // lost last sibling?
00526             if (siblingTable->size() == 0) {
00527                 join();
00528                 return true;
00529             }
00530 
00531             BUCKET_CONSISTENCY(routingTimeout: is sibling);
00532 
00533             // try to refill with new closest contact
00534             refillSiblingTable();
00535 
00536             // call update() for removed sibling
00537             deleteOverlayNeighborArrow(oldSibling);
00538             callUpdate(oldSibling, false);
00539 
00540             updateTooltip();
00541 
00542             return true;
00543         }
00544     }
00545 
00546     /* check if node is already in a bucket ---------------------------------*/
00547     KademliaBucket* bucket = routingBucket(key, false);
00548     if (bucket != NULL && (i = bucket->findIterator(key) ) != bucket->end() ) {
00549 
00550         i->incStaleCount();
00551         i->setPingSent(false);
00552 
00553         if (i->getStaleCount() > maxStaleCount || immediately) {
00554             // remove from routing table
00555             bucket->erase(i);
00556 
00557             if (enableReplacementCache) {
00558                 if (bucket->replacementCache.size()) {
00559                     routingAdd(bucket->replacementCache.front(), true,
00560                                bucket->replacementCache.front().getRtt());
00561                     bucket->replacementCache.pop_front();
00562                     nodesReplaced++;
00563                 }
00564             }
00565         }
00566 
00567         BUCKET_CONSISTENCY(routingTimeout: is in bucket);
00568         return true;
00569     }
00570     BUCKET_CONSISTENCY(routingTimeout: end);
00571     return false;
00572 }
00573 
00574 void Kademlia::refillSiblingTable()
00575 {
00576     if (siblingTable->size() == 0 ||
00577         siblingTable->isFull())
00578         return;
00579 
00580     int index = routingBucketIndex(siblingTable->back().getKey()) - 1;
00581     assert(index > 0);
00582 
00583     while ((routingTable[index] == NULL ||
00584             routingTable[index]->empty()) &&
00585             index < (int)(OverlayKey::getLength() - 1)) {
00586         index++;
00587     }
00588     if (index < (int)OverlayKey::getLength() &&
00589             routingTable[index] != NULL && routingTable[index]->size()) {
00590 
00591         KademliaBucket sortedBucket(k, comparator);
00592         for (uint32_t i = 0; i < routingTable[index]->size(); ++i) {
00593             sortedBucket.add(routingTable[index]->at(i));
00594         }
00595 
00596         siblingTable->add(sortedBucket.front());
00597 
00598         // call update() for new sibling
00599         if (!secureMaintenance) {
00600             showOverlayNeighborArrow(sortedBucket.front(), false,
00601                                      "m=m,50,100,50,100;ls=green,1");
00602             callUpdate(sortedBucket.front(), true);
00603         }
00604 
00605         // remove node from bucket
00606         routingTable[index]->erase(routingTable[index]->
00607               findIterator(sortedBucket.front().getKey()));
00608         assert(siblingTable->isFull());
00609         BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable());
00610     }
00611 }
00612 
00613 void Kademlia::setBucketUsage(const OverlayKey& key)
00614 {
00615     KademliaBucket* bucket = routingBucket(key, true);
00616 
00617     if (bucket) {
00618         bucket->setLastUsage(simTime());
00619     }
00620 
00621     if (((siblingTable->size() + 1) < (uint32_t)getMaxNumSiblings())
00622         || ((siblingTable->at(getMaxNumSiblings() - 2).getKey() ^ thisNode.getKey())
00623                 >= (key ^ thisNode.getKey()))) {
00624         siblingTable->setLastUsage(simTime());
00625     }
00626 
00627 }
00628 
00629 bool Kademlia::isSiblingFor(const NodeHandle& node, const OverlayKey& key,
00630                             int numSiblings, bool* err)
00631 {
00632     if (key.isUnspecified())
00633         error("Kademlia::isSiblingFor(): key is unspecified!");
00634 
00635     if (state != READY) {
00636         EV << "[Kademlia::isSiblingFor()] @ "
00637            << thisNode.getAddress()
00638            << " (" << thisNode.getKey().toString(16) << ")]\n"
00639            << "    state != READY"
00640            << endl;
00641         *err = true;
00642         return false;
00643     }
00644 
00645     if (numSiblings > getMaxNumSiblings()) {
00646         opp_error("Kademlia::isSiblingFor(): numSiblings too big!");
00647     }
00648 
00649     // set default number of siblings to consider
00650     if (numSiblings == -1) {
00651         numSiblings = getMaxNumSiblings();
00652     }
00653 
00654     if (numSiblings == 0) {
00655         *err = false;
00656         return (node.getKey() == key);
00657     }
00658 
00659     if (siblingTable->size() < (uint)numSiblings) {
00660         *err = false;
00661         return true;
00662     }
00663 
00664     if (siblingTable->isFull() &&
00665         ((thisNode.getKey() ^ key) >
00666          (thisNode.getKey() ^ siblingTable->back().getKey()))) {
00667         EV << "[Kademlia::isSiblingFor()] @ "
00668            << thisNode.getAddress()
00669            << " (" << thisNode.getKey().toString(16) << ")]\n"
00670            << "    Not sure if I am sibling for " << key << " !\n"
00671            << "    (" << key << " is not closer to me than "
00672            << siblingTable->back().getKey() << ")"
00673            << endl;
00674         *err = true;
00675         return false;
00676     }
00677 
00678     KeyDistanceComparator<KeyXorMetric>* comp =
00679         new KeyDistanceComparator<KeyXorMetric>(key);
00680 
00681     // create result vector
00682     NodeVector* result = new NodeVector(numSiblings, comp);
00683 
00684     for (KademliaBucket::iterator i=siblingTable->begin();
00685          i != siblingTable->end(); i++) {
00686         result->add( *i);
00687     }
00688 
00689     // add local node
00690     result->add(thisNode);
00691 
00692     *err = false;
00693     delete comp;
00694 
00695     if (result->contains(node.getKey())) {
00696         delete result;
00697         return true;
00698     } else {
00699         delete result;
00700         assert(!(numSiblings == 1 && key == node.getKey()));
00701         return false;
00702     }
00703 }
00704 
00705 void Kademlia::handleNodeGracefulLeaveNotification()
00706 {
00707     // send failed node call to all siblings
00708     FailedNodeCall* call = new FailedNodeCall();
00709     call->setFailedNode(getThisNode());
00710     call->setBitLength(FAILEDNODECALL_L(call));
00711     for (KademliaBucket::iterator i = siblingTable->begin();
00712          i != siblingTable->end(); i++) {
00713         countFailedNodeCall(call);
00714         sendUdpRpcCall(*i, call->dup());
00715     }
00716 
00717     delete call;
00718 }
00719 
00720 bool Kademlia::handleFailedNode(const TransportAddress& failed)
00721 {
00722     assert(!failed.isUnspecified());
00723 
00724     KademliaBucket::iterator i;
00725     // check sibling table
00726     for (i = siblingTable->begin(); i != siblingTable->end(); ++i) {
00727         if (failed == *i) break;
00728     }
00729 
00730     if (i != siblingTable->end()) {
00731         // remove from sibling table
00732         NodeHandle oldSibling = *i;
00733         siblingTable->erase(i);
00734 
00735         // call update() for removed sibling
00736         deleteOverlayNeighborArrow(oldSibling);
00737         callUpdate(oldSibling, false);
00738 
00739         updateTooltip();
00740 
00741         // try to refill with new closest contact
00742         refillSiblingTable();
00743     } else {
00744         // check buckets
00745         uint32_t m;
00746         for (m = 0; m < routingTable.size(); ++m) {
00747             if (routingTable[m] != NULL) {
00748                 for (i = routingTable[m]->begin(); i != routingTable[m]->end();
00749                      ++i) {
00750                     if (failed == *i) {
00751                         // remove from routing table
00752                         routingTable[m]->erase(i);
00753                         return (siblingTable->size() != 0);
00754                     }
00755                 }
00756             }
00757         }
00758     }
00759     return (siblingTable->size() != 0);
00760 }
00761 
00762 NodeVector* Kademlia::findNode(const OverlayKey& key, int numRedundantNodes,
00763                                int numSiblings, BaseOverlayMessage* msg)
00764 {
00765     if (numSiblings > getMaxNumSiblings()) {
00766         opp_error("(Kademlia::findNode()) numRedundantNodes or numSiblings "
00767                   "too big!");
00768     }
00769 
00770 #if 0
00771     if (numRedundantNodes < 2) {
00772         throw cRuntimeError("Kademlia::findNode(): For Kademlia "
00773                                 "redundantNodes must be at least 2 "
00774                                 "and lookupMerge should be true!");
00775     }
00776 #endif
00777 
00778     // create temporary comparator
00779     KeyDistanceComparator<KeyXorMetric>* comp =
00780         new KeyDistanceComparator<KeyXorMetric>( key );
00781 
00782     // select result set size
00783     bool err;
00784     int resultSize;
00785 
00786     if (numSiblings < 0) {
00787         // exhaustive iterative doesn't care about siblings
00788         resultSize = numRedundantNodes;
00789     } else {
00790         resultSize = isSiblingFor(thisNode, key, numSiblings, &err) ?
00791                 (numSiblings ? numSiblings : 1) : numRedundantNodes;
00792     }
00793     assert(numSiblings || numRedundantNodes);
00794 
00795     NodeVector* result = new NodeVector(resultSize, comp);
00796 
00797     if (siblingTable->isEmpty()) {
00798         result->add(thisNode);
00799         delete comp;
00800         return result;
00801     }
00802 
00803     // add items from buckets
00804     int index;
00805     int mainIndex = routingBucketIndex(key);
00806     int startIndex = routingBucketIndex(key, true);
00807     int endIndex = routingBucketIndex(siblingTable->back().getKey());
00808 
00809     // add nodes from best fitting bucket
00810     if (mainIndex != -1) {
00811         KademliaBucket* bucket = routingTable[mainIndex];
00812         if (bucket != NULL && bucket->size()) {
00813             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00814                 result->add(*i);
00815                 //EV << "Kademlia::findNode(): Adding "
00816                 //   << *i << " from bucket " << mainIndex << endl;
00817             }
00818         }
00819     }
00820 
00821     // add most fitting buckets
00822     if (startIndex >= endIndex || !result->isFull()) {
00823         for (index = startIndex; index >= endIndex; --index) {
00824             // add bucket to result vector
00825             if (index == mainIndex) continue;
00826             KademliaBucket* bucket = routingTable[index];
00827             if (bucket != NULL && bucket->size()) {
00828                 for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00829                     result->add(*i);
00830                     //EV << "Kademlia::routingGetClosestNodes(): Adding "
00831                     //   << *i << " from bucket " << index << endl;
00832                 }
00833             }
00834         }
00835 
00836         // add nodes from sibling table
00837         for (KademliaBucket::iterator i = siblingTable->begin();
00838              i != siblingTable->end(); i++) {
00839             result->add(*i);
00840         }
00841         // add local node
00842         result->add(thisNode);
00843     }
00844 
00845     // add more distant buckets
00846     for (index = mainIndex + 1; !result->isFull() && index < numBuckets;
00847          ++index) {
00848         // add bucket to result vector
00849         KademliaBucket* bucket = routingTable[index];
00850         if (bucket != NULL && bucket->size()) {
00851             for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
00852                 result->add(*i);
00853                 //EV << "[Kademlia::routingGetClosestNodes()]\n"
00854                 //   << "    Adding " << *i << " from bucket " << index
00855                 //   << endl;
00856             }
00857         }
00858     }
00859 
00860     delete comp;
00861 
00862     return result;
00863 }
00864 
00865 //-----------------------------------------------------------------------------
00866 
00867 
00868 void Kademlia::handleTimerEvent(cMessage* msg)
00869 {
00870     if (msg == bucketRefreshTimer) {
00871         handleBucketRefreshTimerExpired();
00872     } else if (msg == siblingPingTimer) {
00873         if (siblingPingInterval == 0) {
00874             return;
00875         }
00876 
00877         for (KademliaBucket::iterator i = siblingTable->begin();
00878              i != siblingTable->end(); i++) {
00879             pingNode(*i);
00880         }
00881         scheduleAt(simTime() + siblingPingInterval, msg);
00882     }
00883 }
00884 
00885 //In Kademlia this method is used to maintain the routing table.
00886 bool Kademlia::handleRpcCall(BaseCallMessage* msg)
00887 {
00888     bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
00889     RPC_SWITCH_START(msg)
00890     RPC_ON_CALL(Ping) {
00891         // add active node
00892         OverlayCtrlInfo* ctrlInfo =
00893             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00894         routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
00895         break;
00896     }
00897     RPC_ON_CALL(FindNode)
00898     {
00899         // add active node
00900         OverlayCtrlInfo* ctrlInfo =
00901             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00902         routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
00903         break;
00904     }
00905     RPC_SWITCH_END()
00906     return false;
00907 }
00908 
00909 //In Kademlia this method is used to maintain the routing table.
00910 void Kademlia::handleRpcResponse(BaseResponseMessage* msg,
00911                                  cPolymorphic* context, int rpcId,
00912                                  simtime_t rtt)
00913 {
00914     bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
00915     OverlayCtrlInfo* ctrlInfo =
00916         dynamic_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00917     NodeHandle srcRoute = (ctrlInfo ? ctrlInfo->getSrcRoute()
00918                                     : msg->getSrcNode());
00919 
00920     RPC_SWITCH_START(msg)
00921         RPC_ON_RESPONSE(Ping) {
00922             if (state == INIT) {
00923                 // schedule bucket refresh timer
00924                 cancelEvent(bucketRefreshTimer);
00925                 scheduleAt(simTime(), bucketRefreshTimer);
00926                 cancelEvent(siblingPingTimer);
00927                 scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
00928                 state = JOIN;
00929             }
00930         }
00931         RPC_ON_RESPONSE(FindNode)
00932         {
00933             if (state == INIT) {
00934                 state = JOIN;
00935 
00936                 // bootstrap node is trustworthy: add all nodes immediately
00937                 routingAdd(srcRoute, true, rtt, maintenanceLookup);
00938                 for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
00939                     routingAdd(_FindNodeResponse->getClosestNodes(i), true,
00940                                MAXTIME-1, maintenanceLookup);
00941 
00942                 if (newMaintenance) {
00943                     createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
00944                                        new KademliaLookupListener(this));
00945                 } else {
00946                     // schedule bucket refresh timer
00947                     cancelEvent(bucketRefreshTimer);
00948                     scheduleAt(simTime(), bucketRefreshTimer);
00949                     cancelEvent(siblingPingTimer);
00950                     scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
00951                 }
00952 
00953                 break;
00954             }
00955 
00956             // add active node
00957             if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
00958                 defaultRoutingType == FULL_RECURSIVE_ROUTING ||
00959                 defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
00960                 rtt = MAXTIME;
00961             }
00962             setBucketUsage(srcRoute.getKey());
00963 
00964             // add inactive nodes
00965             for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
00966                 routingAdd(_FindNodeResponse->getClosestNodes(i), false,
00967                            MAXTIME, maintenanceLookup);
00968             break;
00969         }
00970     RPC_SWITCH_END()
00971 
00972     // add node that responded
00973     routingAdd(srcRoute, true, rtt, maintenanceLookup);
00974 }
00975 
00976 // In Kademlia this method is used to maintain the routing table.
00977 void Kademlia::handleRpcTimeout(BaseCallMessage* msg,
00978                                 const TransportAddress& dest,
00979                                 cPolymorphic* context, int rpcId,
00980                                 const OverlayKey& destKey)
00981 {
00982     if (dest.isUnspecified()) return;
00983     try {
00984         RPC_SWITCH_START(msg)
00985         RPC_ON_CALL(Ping) {
00986             if (state == INIT) {
00987                 joinOverlay();
00988                 return;
00989             }
00990 
00991             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
00992             routingTimeout(handle.getKey());
00993             break;
00994         }
00995         RPC_ON_CALL(FindNode) {
00996             if (state == INIT) {
00997                 joinOverlay();
00998                 return;
00999             }
01000 
01001             const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
01002             routingTimeout(handle.getKey());
01003             setBucketUsage(handle.getKey());
01004             break;
01005         }
01006         RPC_SWITCH_END()
01007     } catch (...) {
01008         EV << "[Kademlia:handleRpcTimout() @ " << thisNode.getAddress()
01009            << " (" << thisNode.getKey().toString(16) << ")]\n"
01010            << "    ERROR: RPC timeout without key ("
01011            << msg << " -> " << dest << ")" << endl;
01012         return;
01013     }
01014 }
01015 
01016 void Kademlia::lookupFinished(bool isValid)
01017 {
01018     if (state == JOIN) {
01019         cancelEvent(bucketRefreshTimer);
01020 
01021         if (siblingTable->size() == 0) {
01022             // initial lookup failed - get new bootstrap node
01023             joinOverlay();
01024             return;
01025         }
01026 
01027         scheduleAt(simTime(), bucketRefreshTimer);
01028 
01029         if (!newMaintenance) {
01030             state = READY;
01031             setOverlayReady(true);
01032         }
01033     }
01034 }
01035 
01036 // handle a expired bucket refresh timer
01037 void Kademlia::handleBucketRefreshTimerExpired()
01038 {
01039     // refresh buckets
01040     if (state != READY || (((simTime() - siblingTable->getLastUsage()) >
01041                             minSiblingTableRefreshInterval))) {
01042         if (exhaustiveRefresh) {
01043             //TODO config shit
01044             int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
01045             iterativeLookupConfig.redundantNodes = siblingRefreshNodes;
01046             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
01047                  getThisNode().getKey(), siblingRefreshNodes,
01048                  hopCountMax, 0, new KademliaLookupListener(this));
01049             iterativeLookupConfig.redundantNodes = baseRedundantNodes;
01050         } else if (newMaintenance) {
01051             //for (KademliaBucket::iterator i = siblingTable->begin();
01052             //     i != siblingTable->end(); i++) {
01053 
01054             //    sendSiblingFindNodeCall(*i);
01055             //}
01056             if (siblingTable->size()) {
01057                 sendSiblingFindNodeCall(siblingTable->at(intuniform(0,siblingTable->size()-1)));
01058             }
01059             state = READY;
01060             setOverlayReady(true);
01061         } else {
01062             createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
01063                                    new KademliaLookupListener(this));
01064         }
01065         siblingTable->setLastUsage(simTime());
01066         ++siblingTableRefreshCount;
01067     }
01068 
01069     if (state == READY) {
01070         if (siblingTable->size()) {
01071             // get bit index of most significant digit that differs
01072             // from our next sibling's key to prevent us from refreshing
01073             // buckets, which can't contain any nodes
01074             int32_t diff = OverlayKey::getLength() - b*(getThisNode().getKey().
01075                 sharedPrefixLength(siblingTable->front().getKey(), b) + 1);
01076             int bucketsRefreshedPerTask = 0;
01077             for (int32_t i = OverlayKey::getLength() - b; i >= diff; i -=b ) {
01078                 for (int32_t d=0; d < ((1 << b) - 1); d++) {
01079                     int32_t index = (i / b) * ((1 << b) - 1) + d;
01080                     if (index < 0) continue;
01081                     if ((routingTable[index] == NULL) ||
01082                         ((simTime() - routingTable[index]->getLastUsage()) >
01083                         minBucketRefreshInterval)) {
01084 
01085                         OverlayKey refreshKey =
01086                             getThisNode().getKey() ^ (OverlayKey(d+1) << i);
01087 
01088                         if (exhaustiveRefresh) {
01089                             //TODO config stuff
01090                             int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
01091                             iterativeLookupConfig.redundantNodes = bucketRefreshNodes;
01092                             createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
01093                                 refreshKey, bucketRefreshNodes, hopCountMax,
01094                                 0, new KademliaLookupListener(this));
01095                             iterativeLookupConfig.redundantNodes = baseRedundantNodes;
01096                         } else {
01097                             createLookup()->lookup(refreshKey, s, hopCountMax, 0,
01098                                              new KademliaLookupListener(this));
01099                         }
01100 
01101                         ++bucketsRefreshedPerTask;
01102                         ++bucketRefreshCount;
01103                         setBucketUsage(refreshKey);
01104                     }
01105                 }
01106             }
01107             RECORD_STATS(globalStatistics->recordOutVector(
01108                                    "Kademlia: Buckets Refreshed Per Task",
01109                                    bucketsRefreshedPerTask));
01110         }
01111         // schedule next bucket refresh process
01112         cancelEvent(bucketRefreshTimer);
01113         scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval,
01114                         minBucketRefreshInterval) / 10.0), bucketRefreshTimer);
01115     }
01116 }
01117 
01118 //virtual public: xor metric
01119 OverlayKey Kademlia::distance(const OverlayKey& x,
01120                               const OverlayKey& y,
01121                               bool useAlternative) const
01122 {
01123     if (!useAlternative) return x^y; // KeyXorMetric().distance(x, y);
01124     return KeyPrefixMetric().distance(x, y);
01125 }
01126 
01127 void Kademlia::updateTooltip()
01128 {
01129     if (ev.isGUI()) {
01130         std::stringstream ttString;
01131 
01132         // show our nodeId in a tooltip
01133         ttString << "This: " << thisNode << endl << "Siblings: "
01134                  << siblingTable->size();
01135 
01136         getParentModule()->getParentModule()->getDisplayString().
01137         setTagArg("tt", 0, ttString.str().c_str());
01138         getParentModule()->getDisplayString().
01139         setTagArg("tt", 0, ttString.str().c_str());
01140         getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
01141     }
01142 }
01143 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3