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