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