00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00100 kbr = true;
00101
00102
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
00132 numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b);
00133
00134
00135 siblingTable = new KademliaBucket(s * 5, NULL);
00136
00137
00138 routingTable.assign(numBuckets, (KademliaBucket*)NULL);
00139
00140 WATCH_VECTOR(*siblingTable);
00141 WATCH_VECTOR(routingTable);
00142
00143
00144 bucketRefreshTimer = new cMessage("bucketRefreshTimer");
00145 siblingPingTimer = new cMessage("siblingPingTimer");
00146
00147
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
00200 if (!thisNode.getKey().isUnspecified()) {
00201 bootstrapList->removeBootstrapNode(thisNode);
00202 }
00203
00204
00205 routingDeinit();
00206 routingInit();
00207
00208 TransportAddress handle = bootstrapList->getBootstrapNode();
00209
00210 if (!handle.isUnspecified()) {
00211 if (secureMaintenance) {
00212 sendSiblingFindNodeCall(handle);
00213 } else {
00214
00215 pingNode(handle);
00216 }
00217 } else {
00218
00219 state = READY;
00220 setOverlayReady(true);
00221
00222
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
00235 state = INIT;
00236
00237 setOverlayReady(false);
00238
00239
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
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
00281 OverlayKey delta = key ^ getThisNode().getKey();
00282
00283
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
00300 int num = routingBucketIndex(key);
00301 if (num < 0)
00302 return NULL;
00303
00304
00305 KademliaBucket* bucket = routingTable[ num ];
00306 if (bucket == NULL && ensure)
00307 bucket = routingTable[ num ] = new KademliaBucket( k, comparator );
00308
00309
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
00318 if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey() )
00319 return false;
00320
00321
00322 KademliaBucket::iterator i;
00323 bool result = false;
00324 bool authenticated = (isAlive && (rtt != MAXTIME));
00325
00326
00327 KademliaBucketEntry kadHandle = handle;
00328 kadHandle.setRtt(rtt);
00329 kadHandle.setLastSeen(simTime());
00330
00331
00332 if ((i = siblingTable->findIterator(handle.getKey()))
00333 != siblingTable->end()) {
00334
00335 if (isAlive) {
00336 if (!secureMaintenance || authenticated) {
00337 if (kadHandle.getRtt() == MAXTIME) {
00338 kadHandle.setRtt(i->getRtt());
00339 }
00340
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
00350
00351 pingNode(handle);
00352 return false;
00353 }
00354 }
00355 }
00356 BUCKET_CONSISTENCY(routingAdd: node is sibling);
00357 return true;
00358 }
00359
00360
00361 KademliaBucket* bucket = routingBucket(handle.getKey(), false);
00362 if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) )
00363 != bucket->end() ) {
00364
00365 if (isAlive) {
00366 if (!secureMaintenance || authenticated) {
00367 if (kadHandle.getRtt() == MAXTIME) {
00368 kadHandle.setRtt(i->getRtt());
00369 }
00370
00371
00372 bucket->erase(i);
00373
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
00383
00384 pingNode(handle);
00385 return false;
00386 }
00387 }
00388 }
00389
00390 BUCKET_CONSISTENCY(routingAdd: node is in bucket);
00391 return true;
00392 }
00393
00394
00395 if (siblingTable->isAddable(handle) ) {
00396 if (secureMaintenance && !authenticated) {
00397 if (!maintenanceLookup || (isAlive && (rtt == MAXTIME))) {
00398
00399
00400 pingNode(handle);
00401 } else if (newMaintenance) {
00402
00403
00404 pingNode(handle);
00405 }
00406 return false;
00407 }
00408
00409 bool finished = false;
00410 int siblingPos = -1;
00411
00412
00413 if (siblingTable->isFull()) {
00414
00415 KademliaBucketEntry oldHandle = siblingTable->back();
00416 assert(oldHandle.getKey() != kadHandle.getKey());
00417
00418
00419 siblingPos = siblingTable->add(kadHandle);
00420
00421
00422 kadHandle = oldHandle;
00423
00424
00425 if (!secureMaintenance) {
00426 deleteOverlayNeighborArrow(oldHandle);
00427 callUpdate(oldHandle, false);
00428 }
00429
00430
00431 result = true;
00432 } else {
00433
00434 siblingPos = siblingTable->add(kadHandle);
00435
00436
00437 finished = true;
00438 }
00439 assert(siblingPos > -1);
00440
00441
00442 if ((pingNewSiblings && !isAlive)) {
00443 pingNode(handle);
00444 }
00445
00446 updateTooltip();
00447
00448
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
00460 bucket = routingBucket(kadHandle.getKey(), true);
00461 if (!bucket->isFull()) {
00462
00463 if (secureMaintenance && !authenticated) {
00464 if ((isAlive && (rtt == MAXTIME))) {
00465
00466
00467
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
00508 if (key.isUnspecified())
00509 return false;
00510
00511
00512 KademliaBucket::iterator i;
00513
00514
00515 if ((i = siblingTable->findIterator(key)) != siblingTable->end()) {
00516
00517 i->incStaleCount();
00518 i->setPingSent(false);
00519
00520 if (i->getStaleCount() > maxStaleCount || immediately) {
00521
00522 NodeHandle oldSibling = *i;
00523 siblingTable->erase(i);
00524
00525
00526 if (siblingTable->size() == 0) {
00527 join();
00528 return true;
00529 }
00530
00531 BUCKET_CONSISTENCY(routingTimeout: is sibling);
00532
00533
00534 refillSiblingTable();
00535
00536
00537 deleteOverlayNeighborArrow(oldSibling);
00538 callUpdate(oldSibling, false);
00539
00540 updateTooltip();
00541
00542 return true;
00543 }
00544 }
00545
00546
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
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
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
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
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
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
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
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
00726 for (i = siblingTable->begin(); i != siblingTable->end(); ++i) {
00727 if (failed == *i) break;
00728 }
00729
00730 if (i != siblingTable->end()) {
00731
00732 NodeHandle oldSibling = *i;
00733 siblingTable->erase(i);
00734
00735
00736 deleteOverlayNeighborArrow(oldSibling);
00737 callUpdate(oldSibling, false);
00738
00739 updateTooltip();
00740
00741
00742 refillSiblingTable();
00743 } else {
00744
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
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
00779 KeyDistanceComparator<KeyXorMetric>* comp =
00780 new KeyDistanceComparator<KeyXorMetric>( key );
00781
00782
00783 bool err;
00784 int resultSize;
00785
00786 if (numSiblings < 0) {
00787
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
00804 int index;
00805 int mainIndex = routingBucketIndex(key);
00806 int startIndex = routingBucketIndex(key, true);
00807 int endIndex = routingBucketIndex(siblingTable->back().getKey());
00808
00809
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
00816
00817 }
00818 }
00819 }
00820
00821
00822 if (startIndex >= endIndex || !result->isFull()) {
00823 for (index = startIndex; index >= endIndex; --index) {
00824
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
00831
00832 }
00833 }
00834 }
00835
00836
00837 for (KademliaBucket::iterator i = siblingTable->begin();
00838 i != siblingTable->end(); i++) {
00839 result->add(*i);
00840 }
00841
00842 result->add(thisNode);
00843 }
00844
00845
00846 for (index = mainIndex + 1; !result->isFull() && index < numBuckets;
00847 ++index) {
00848
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
00854
00855
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
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
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
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
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
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
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
00947 cancelEvent(bucketRefreshTimer);
00948 scheduleAt(simTime(), bucketRefreshTimer);
00949 cancelEvent(siblingPingTimer);
00950 scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
00951 }
00952
00953 break;
00954 }
00955
00956
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
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
00973 routingAdd(srcRoute, true, rtt, maintenanceLookup);
00974 }
00975
00976
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
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
01037 void Kademlia::handleBucketRefreshTimerExpired()
01038 {
01039
01040 if (state != READY || (((simTime() - siblingTable->getLastUsage()) >
01041 minSiblingTableRefreshInterval))) {
01042 if (exhaustiveRefresh) {
01043
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
01052
01053
01054
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
01072
01073
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
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
01112 cancelEvent(bucketRefreshTimer);
01113 scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval,
01114 minBucketRefreshInterval) / 10.0), bucketRefreshTimer);
01115 }
01116 }
01117
01118
01119 OverlayKey Kademlia::distance(const OverlayKey& x,
01120 const OverlayKey& y,
01121 bool useAlternative) const
01122 {
01123 if (!useAlternative) return 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
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