#include <Kademlia.h>

Public Member Functions | |
| Kademlia () | |
| ~Kademlia () | |
| void | initializeOverlay (int stage) |
| Initializes derived-class-attributes. | |
| void | finishOverlay () |
| collects statistical data in derived class | |
| void | joinOverlay () |
| Join the overlay with a given nodeID in thisNode.key. | |
| bool | isSiblingFor (const NodeHandle &node, const OverlayKey &key, int numSiblings, bool *err) |
| Query if a node is among the siblings for a given key. | |
| int | getMaxNumSiblings () |
| Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol. | |
| int | getMaxNumRedundantNodes () |
| Query the maximum number of redundant next hop nodes that are returned by findNode(). | |
| void | handleTimerEvent (cMessage *msg) |
| bool | handleRpcCall (BaseCallMessage *msg) |
| Processes Remote-Procedure-Call invocation messages. | |
Protected Member Functions | |
| NodeVector * | findNode (const OverlayKey &key, int numRedundantNodes, int numSiblings, BaseOverlayMessage *msg) |
| Implements the find node call. | |
| void | handleRpcResponse (BaseResponseMessage *msg, cPolymorphic *context, int rpcId, simtime_t rtt) |
| This method is called if an RPC response has been received. | |
| void | handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, cPolymorphic *context, int rpcId, const OverlayKey &destKey) |
| This method is called if an RPC timeout has been reached. | |
| void | handleBucketRefreshTimerExpired () |
| handle a expired bucket refresh timer | |
| OverlayKey | distance (const OverlayKey &x, const OverlayKey &y) const |
| This method should implement the distance between two keys. | |
| void | updateTooltip () |
| updates information shown in GUI | |
| virtual void | lookupFinished (bool isValid) |
Protected Attributes | |
| uint32_t | k |
| uint32_t | b |
| uint32_t | s |
| uint32_t | maxStaleCount |
| bool | exhaustiveRefresh |
| bool | pingNewSiblings |
| simtime_t | minSiblingTableRefreshInterval |
| simtime_t | minBucketRefreshInterval |
| cMessage * | bucketRefreshTimer |
Private Member Functions | |
| void | routingInit () |
| void | routingDeinit () |
| int | routingBucketIndex (const OverlayKey &key, bool firstOnLayer=false) |
| Returns the index of the bucket the key would reside with respect to Kademlia parameters. | |
| KademliaBucket * | routingBucket (const OverlayKey &key, bool ensure) |
Returns a Bucket or NULL if the bucket has not yet allocated. | |
| bool | routingAdd (const NodeHandle &handle, bool isAlive, simtime_t rtt=MAXTIME) |
| Adds a node to the routing table. | |
| bool | routingRemove (const OverlayKey &key) |
| Removes a node from the routing table. | |
| bool | routingTimeout (const OverlayKey &key, bool immediately=false) |
| Removes a node after a number of timeouts or immediately if immediately is true (behaves like routingRemove). | |
| void | refillSiblingTable () |
| void | setBucketUsage (const OverlayKey &key) |
| bool | handleFailedNode (const TransportAddress &failed) |
| Handles a failed node. | |
Private Attributes | |
| uint32_t | bucketRefreshCount |
| uint32_t | siblingTableRefreshCount |
| uint32_t | nodesReplaced |
| KeyDistanceComparator < KeyXorMetric > * | comparator |
| KademliaBucket * | siblingTable |
| std::vector< KademliaBucket * > | routingTable |
| int | numBuckets |
| std::map< NodeHandle, NodeHandle > | replacementCache |
Friends | |
| class | KademliaLookupListener |
Definition at line 42 of file Kademlia.h.
| Kademlia::Kademlia | ( | ) |
Definition at line 136 of file Kademlia.cc.
00137 { 00138 siblingTable = NULL; 00139 comparator = NULL; 00140 }
| Kademlia::~Kademlia | ( | ) |
Definition at line 142 of file Kademlia.cc.
00143 { 00144 routingDeinit(); 00145 00146 replacementCache.clear(); 00147 delete siblingTable; 00148 delete comparator; 00149 cancelAndDelete(bucketRefreshTimer); 00150 }
| OverlayKey Kademlia::distance | ( | const OverlayKey & | x, | |
| const OverlayKey & | y | |||
| ) | const [protected, virtual] |
This method should implement the distance between two keys.
It may be overloaded to implement a new metric. The default implementation uses the standard-metric d = abs(x-y).
| x | Left-hand-side Key | |
| y | Right-hand-side key |
Reimplemented from BaseOverlay.
Definition at line 989 of file Kademlia.cc.
| NodeVector * Kademlia::findNode | ( | const OverlayKey & | key, | |
| int | numRedundantNodes, | |||
| int | numSiblings, | |||
| BaseOverlayMessage * | msg | |||
| ) | [protected, virtual] |
Implements the find node call.
This method simply returns the closest nodes known in the corresponding routing topology. If the node is a sibling for this key (isSiblingFor(key) = true), this method returns all numSiblings siblings, with the closest neighbor to the key first.
| key | The lookup key. | |
| numRedundantNodes | Maximum number of next hop nodes to return. | |
| numSiblings | number of siblings to return | |
| msg | A pointer to the BaseRouteMessage or FindNodeCall message of this lookup. |
Reimplemented from BaseOverlay.
Definition at line 678 of file Kademlia.cc.
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 // create temporary comparator 00695 KeyDistanceComparator<KeyXorMetric>* comp = 00696 new KeyDistanceComparator<KeyXorMetric>( key ); 00697 00698 // select result set size 00699 bool err; 00700 int resultSize; 00701 00702 if (numSiblings < 0) { 00703 // exhaustive iterative doesn't care about siblings 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 // add items from buckets 00720 int index; 00721 int mainIndex = routingBucketIndex(key); 00722 int startIndex = routingBucketIndex(key, true); 00723 int endIndex = routingBucketIndex(siblingTable->back().getKey()); 00724 00725 // add nodes from best fitting bucket 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 //EV << "Kademlia::findNode(): Adding " 00732 // << *i << " from bucket " << mainIndex << endl; 00733 } 00734 } 00735 } 00736 00737 // add most fitting buckets 00738 if (startIndex >= endIndex || !result->isFull()) { 00739 for (index = startIndex; index >= endIndex; --index) { 00740 // old code... 00741 /* 00742 for (int i = 1; !result->isFull() && i < numBuckets * 3; i++) { 00743 int index = mainIndex + (((i & 1) == 1) ? -1 : 1) * (i / 2); 00744 if (index < 0 || index >= numBuckets) 00745 continue; 00746 */ 00747 00748 // add bucket to result vector 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 //EV << "Kademlia::routingGetClosestNodes(): Adding " 00755 // << *i << " from bucket " << index << endl; 00756 } 00757 } 00758 } 00759 00760 // add nodes from sibling table 00761 for (KademliaBucket::iterator i = siblingTable->begin(); 00762 i != siblingTable->end(); i++) { 00763 result->add(*i); 00764 } 00765 // add local node 00766 result->add(thisNode); 00767 } 00768 00769 // add more distant buckets 00770 for (index = mainIndex + 1; !result->isFull() && index < numBuckets; 00771 ++index) { 00772 // add bucket to result vector 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 //EV << "[Kademlia::routingGetClosestNodes()]\n" 00778 // << " Adding " << *i << " from bucket " << index 00779 // << endl; 00780 } 00781 } 00782 } 00783 00784 delete comp; 00785 00786 return result; 00787 }
| void Kademlia::finishOverlay | ( | ) | [virtual] |
collects statistical data in derived class
Reimplemented from BaseOverlay.
Definition at line 152 of file Kademlia.cc.
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 }
| int Kademlia::getMaxNumRedundantNodes | ( | ) | [virtual] |
Query the maximum number of redundant next hop nodes that are returned by findNode().
Reimplemented from BaseOverlay.
Definition at line 250 of file Kademlia.cc.
Referenced by findNode().
00251 { 00252 return k; 00253 }
| int Kademlia::getMaxNumSiblings | ( | ) | [virtual] |
Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol.
Reimplemented from BaseOverlay.
Definition at line 245 of file Kademlia.cc.
Referenced by findNode(), handleFailedNode(), isSiblingFor(), routingAdd(), routingTimeout(), and setBucketUsage().
00246 { 00247 return s; 00248 }
| void Kademlia::handleBucketRefreshTimerExpired | ( | ) | [protected] |
handle a expired bucket refresh timer
Definition at line 927 of file Kademlia.cc.
Referenced by handleTimerEvent().
00928 { 00929 // refresh buckets 00930 if (state != READY || (((simTime() - siblingTable->getLastUsage()) > 00931 minSiblingTableRefreshInterval))) { 00932 if (exhaustiveRefresh) { 00933 // TODO: replace redundantNodes by k? 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 // get bit index of most significant digit that differs 00947 // from our next sibling's key to prevent us from refreshing 00948 // buckets, which can't contain any nodes 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 // schedule next bucket refresh process 00982 cancelEvent(bucketRefreshTimer); 00983 scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval, 00984 minBucketRefreshInterval) / 10.0), bucketRefreshTimer); 00985 } 00986 }
| bool Kademlia::handleFailedNode | ( | const TransportAddress & | failed | ) | [private, virtual] |
Handles a failed node.
This method is called whenever a node given by findNode() was unreachable. The default implementation does nothing at all.
| failed | the failed node |
Reimplemented from BaseOverlay.
Definition at line 625 of file Kademlia.cc.
00626 { 00627 assert(!failed.isUnspecified()); 00628 00629 KademliaBucket::iterator i; 00630 // check sibling table 00631 for (i = siblingTable->begin(); i != siblingTable->end(); ++i) { 00632 if (failed == *i) break; 00633 } 00634 00635 if (i != siblingTable->end()) { 00636 // remove from sibling table 00637 NodeHandle oldSibling = *i; 00638 siblingTable->erase(i); 00639 00640 if (siblingTable->size() < (uint32_t)getMaxNumSiblings()) { 00641 // no new replacement sibling 00642 deleteOverlayNeighborArrow(oldSibling); 00643 callUpdate(oldSibling, false); 00644 } else if (comparator->compare(oldSibling.getKey(), 00645 siblingTable->at(getMaxNumSiblings() - 1).getKey()) < 0) { 00646 // failed sibling was replaced by next closest node in siblingTable 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 // try to refill with new closest contact 00658 refillSiblingTable(); 00659 } else { 00660 // check buckets 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 // remove from routing table 00668 routingTable[m]->erase(i); 00669 return (siblingTable->size() != 0); 00670 } 00671 } 00672 } 00673 } 00674 } 00675 return (siblingTable->size() != 0); 00676 }
| bool Kademlia::handleRpcCall | ( | BaseCallMessage * | msg | ) | [virtual] |
Processes Remote-Procedure-Call invocation messages.
This method should be overloaded when the overlay provides RPC functionality.
Reimplemented from BaseRpc.
Definition at line 800 of file Kademlia.cc.
00801 { 00802 RPC_SWITCH_START(msg) 00803 RPC_ON_CALL(Ping) { 00804 // add active node 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 // add active node 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 }
| void Kademlia::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
| cPolymorphic * | context, | |||
| int | rpcId, | |||
| simtime_t | rtt | |||
| ) | [protected, virtual] |
This method is called if an RPC response has been received.
| msg | The response message. | |
| context | Pointer to an optional state object. The object has to be handled/deleted by the handleRpcResponse() code | |
| rpcId | The RPC id. | |
| rtt | The Round-Trip-Time of this RPC |
Reimplemented from RpcListener.
Definition at line 823 of file Kademlia.cc.
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 // schedule bucket refresh timer 00836 cancelEvent(bucketRefreshTimer); 00837 scheduleAt(simTime(), bucketRefreshTimer); 00838 state = JOIN; 00839 } 00840 00841 // delete replacement candidate //TODO 00842 replacementCache.erase(srcRoute); 00843 } 00844 RPC_ON_RESPONSE(FindNode) 00845 { 00846 // add active node 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 // add inactive nodes 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 // add node that responded 00862 routingAdd(srcRoute, true, rtt); 00863 }
| void Kademlia::handleRpcTimeout | ( | BaseCallMessage * | msg, | |
| const TransportAddress & | dest, | |||
| cPolymorphic * | context, | |||
| int | rpcId, | |||
| const OverlayKey & | destKey | |||
| ) | [protected, virtual] |
This method is called if an RPC timeout has been reached.
| msg | The original RPC message. | |
| dest | The destination node | |
| context | Pointer to an optional state object. The object has to be handled/deleted by the handleRpcResponse() code | |
| rpcId | The RPC id. | |
| destKey | the destination OverlayKey |
Reimplemented from RpcListener.
Definition at line 866 of file Kademlia.cc.
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 // remove node from replacementCache 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 }
| void Kademlia::handleTimerEvent | ( | cMessage * | msg | ) | [virtual] |
Reimplemented from BaseRpc.
Definition at line 792 of file Kademlia.cc.
00793 { 00794 if (msg == bucketRefreshTimer) { 00795 handleBucketRefreshTimerExpired(); 00796 } 00797 }
| void Kademlia::initializeOverlay | ( | int | stage | ) | [virtual] |
Initializes derived-class-attributes.
Initializes derived-class-attributes, called by BaseOverlay::initialize(). By default this method is called once. If more stages are needed one can overload numInitStages() and add more stages.
| stage | the init stage |
Reimplemented from BaseOverlay.
Definition at line 94 of file Kademlia.cc.
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 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 // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b ) 00114 numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b); 00115 00116 // init routing and sibling table 00117 siblingTable = new KademliaBucket(s * 5, NULL); 00118 00119 // initialize pointers 00120 routingTable.assign(numBuckets, (KademliaBucket*)NULL); 00121 00122 WATCH_VECTOR(*siblingTable); 00123 WATCH_VECTOR(routingTable); 00124 00125 // self-message 00126 bucketRefreshTimer = new cMessage("bucketRefreshTimer"); 00127 00128 // statistics 00129 bucketRefreshCount = 0; 00130 siblingTableRefreshCount = 0; 00131 nodesReplaced = 0; 00132 00133 comparator = NULL; 00134 }
| bool Kademlia::isSiblingFor | ( | const NodeHandle & | node, | |
| const OverlayKey & | key, | |||
| int | numSiblings, | |||
| bool * | err | |||
| ) | [virtual] |
Query if a node is among the siblings for a given key.
Query if a node is among the siblings for a given key. This means, that the nodeId of this node is among the closest numSiblings nodes to the key and that by a local findNode() call all other siblings to this key can be retrieved.
| node | the NodeHandle | |
| key | destination key | |
| numSiblings | The nodes knows all numSiblings nodes close to this key | |
| err | return false if the range could not be determined |
Reimplemented from BaseOverlay.
Definition at line 563 of file Kademlia.cc.
Referenced by findNode().
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 // set default number of siblings to consider 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 // create result vector 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 // add local node 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 }
| void Kademlia::joinOverlay | ( | ) | [virtual] |
Join the overlay with a given nodeID in thisNode.key.
Join the overlay with a given nodeID in thisNode.key. This method may be called by an application to join the overlay with a specific nodeID. It is also called if the node's IP address changes.
Reimplemented from BaseOverlay.
Definition at line 165 of file Kademlia.cc.
00166 { 00167 // remove current node handle from the bootstrap list 00168 if (!thisNode.getKey().isUnspecified()) { 00169 bootstrapList->removeBootstrapNode(thisNode); 00170 } 00171 00172 // initialize routing 00173 routingDeinit(); 00174 routingInit(); 00175 00176 TransportAddress handle = bootstrapList->getBootstrapNode(); 00177 00178 if (!handle.isUnspecified()) { 00179 // ping the bootstrap node to start bootstrapping 00180 pingNode(handle); 00181 00182 /* 00183 FindNodeCall* findNodeCall = new FindNodeCall(); 00184 findNodeCall->setLookupKey(handle.getKey()); 00185 findNodeCall->setSrcNode(getThisNode()); 00186 findNodeCall->setNumRedundantNodes(getMaxNumRedundantNodes()); 00187 findNodeCall->setNumSiblings(getMaxNumSiblings()); 00188 findNodeCall->setBitLength(FINDNODECALL_L(call)); 00189 00190 RECORD_STATS(numFindNodeSent++; 00191 bytesFindNodeSent += findNodeCall->getByteLength()); 00192 00193 sendUdpRpcCall(handle, findNodeCall); 00194 */ 00195 00196 } else { 00197 // we're the only node in the network 00198 state = READY; 00199 setOverlayReady(true); 00200 00201 // schedule bucket refresh timer 00202 cancelEvent(bucketRefreshTimer); 00203 scheduleAt(simTime(), bucketRefreshTimer); 00204 } 00205 }
| void Kademlia::lookupFinished | ( | bool | isValid | ) | [protected, virtual] |
Definition at line 908 of file Kademlia.cc.
Referenced by KademliaLookupListener::lookupFinished().
00909 { 00910 if (state == JOIN) { 00911 cancelEvent(bucketRefreshTimer); 00912 00913 if (siblingTable->size() == 0) { 00914 // initial lookup failed - get new bootstrap node 00915 join(); 00916 return; 00917 } 00918 00919 scheduleAt(simTime(), bucketRefreshTimer); 00920 00921 state = READY; 00922 setOverlayReady(true); 00923 } 00924 }
| void Kademlia::refillSiblingTable | ( | ) | [private] |
Definition at line 512 of file Kademlia.cc.
Referenced by handleFailedNode(), and routingTimeout().
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 // no need to callUpdate(), because s < siblingTable->size(), thus 00533 // new sibling table entry is no real sibling 00534 routingTable[index]-> 00535 erase(routingTable[index]-> 00536 findIterator(sortedBucket.front().getKey())); 00537 assert(siblingTable->isFull()); 00538 BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable()); 00539 } 00540 }
| bool Kademlia::routingAdd | ( | const NodeHandle & | handle, | |
| bool | isAlive, | |||
| simtime_t | rtt = MAXTIME | |||
| ) | [private] |
Adds a node to the routing table.
| handle | handle to add | |
| isAlive | true, if it is known that the node is alive | |
| rtt | measured round-trip-time to node |
Definition at line 290 of file Kademlia.cc.
Referenced by handleRpcCall(), handleRpcResponse(), and routingTimeout().
00291 { 00292 BUCKET_CONSISTENCY(routingAdd: start); 00293 // never add unspecified node handles 00294 if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey() ) 00295 return false; 00296 00297 // bucket index 00298 KademliaBucket::iterator i; 00299 bool result = false; 00300 00301 // convert node handle 00302 KademliaBucketEntry kadHandle = handle; 00303 kadHandle.setRtt(rtt); 00304 kadHandle.setLastSeen(simTime()); 00305 00306 /* check if node is already a sibling -----------------------------------*/ 00307 if ((i = siblingTable->findIterator(handle.getKey())) 00308 != siblingTable->end()) { 00309 // not alive? -> do not change routing information 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 // refresh sibling 00317 (*i) = kadHandle; 00318 } 00319 BUCKET_CONSISTENCY(routingAdd: node is sibling); 00320 return true; 00321 } 00322 00323 /* check if node is already in a bucket ---------------------------------*/ 00324 KademliaBucket* bucket = routingBucket(handle.getKey(), false); 00325 if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) ) 00326 != bucket->end() ) { 00327 // not alive? -> do not change routing information 00328 if (isAlive) { 00329 if (kadHandle.getRtt() == MAXTIME) { 00330 kadHandle.setRtt(i->getRtt()); 00331 } 00332 00333 // remove old handle 00334 bucket->erase(i); 00335 // re-add to tail 00336 bucket->push_back(kadHandle); 00337 bucket->setLastUpdate(simTime()); 00338 } 00339 BUCKET_CONSISTENCY(routingAdd: node is in bucket); 00340 return true; 00341 } 00342 00343 /* check if node can be added to the sibling list -----------------------*/ 00344 if (siblingTable->isAddable(handle) ) { 00345 00346 bool finished = false; 00347 int siblingPos = -1; 00348 00349 // check if sibling list is full so a handle is preemted from the list 00350 if (siblingTable->isFull()) { 00351 // get handle thats about to be preempted 00352 KademliaBucketEntry oldHandle = siblingTable->back(); 00353 assert(oldHandle.getKey() != kadHandle.getKey()); 00354 // add handle to the sibling list 00355 siblingPos = siblingTable->add(kadHandle); 00356 00357 // change, so that the preempted handle is added to a bucket 00358 kadHandle = oldHandle; 00359 00360 // return always true, since the handle has been added 00361 result = true; 00362 } else { 00363 // simply add the handle and stop 00364 siblingPos = siblingTable->add(kadHandle); 00365 00366 // don't need to add kadHandle also to regular buckets 00367 finished = true; 00368 } 00369 assert(siblingPos > -1); 00370 00371 // ping new siblings 00372 if ((pingNewSiblings && !isAlive)) { 00373 pingNode(handle); 00374 } 00375 00376 siblingTable->setLastUpdate(simTime()); 00377 00378 updateTooltip(); 00379 00380 // call update() for real siblings 00381 if (siblingPos < getMaxNumSiblings()) { 00382 if (siblingTable->size() > (uint32_t)getMaxNumSiblings()) { 00383 // removed old sibling 00384 NodeHandle& removedSibling = siblingTable->at(getMaxNumSiblings()); 00385 deleteOverlayNeighborArrow(removedSibling); 00386 callUpdate(removedSibling, false); 00387 } 00388 // new sibling 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 /* add node to the appropriate bucket, if not full ---------------------*/ 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 //TODO parameter for usage of replacement cache 00413 // save candidate, ping head, 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 //TODO paper: probing should be delayed until useful messages are 00422 //there to send to head 00423 pingNode(*it); 00424 } 00425 } 00426 00427 BUCKET_CONSISTENCY(routingAdd: end); 00428 return result; 00429 }
| KademliaBucket * Kademlia::routingBucket | ( | const OverlayKey & | key, | |
| bool | ensure | |||
| ) | [private] |
Returns a Bucket or NULL if the bucket has not yet allocated.
If ensure is true, the bucket allocation is ensured.
| key | The key of the node | |
| ensure | If true, the bucket allocation is ensured |
Definition at line 274 of file Kademlia.cc.
Referenced by routingAdd(), routingTimeout(), and setBucketUsage().
00275 { 00276 // get bucket index 00277 int num = routingBucketIndex(key); 00278 if (num < 0) 00279 return NULL; 00280 00281 // get bucket and allocate if necessary 00282 KademliaBucket* bucket = routingTable[ num ]; 00283 if (bucket == NULL && ensure) 00284 bucket = routingTable[ num ] = new KademliaBucket( k, comparator ); 00285 00286 // return bucket 00287 return bucket; 00288 }
| int Kademlia::routingBucketIndex | ( | const OverlayKey & | key, | |
| bool | firstOnLayer = false | |||
| ) | [private] |
Returns the index of the bucket the key would reside with respect to Kademlia parameters.
| key | The key of the node | |
| firstOnLayer | If true bucket with smallest index on same layer is returned |
Definition at line 255 of file Kademlia.cc.
Referenced by findNode(), refillSiblingTable(), routingAdd(), and routingBucket().
00256 { 00257 // calculate XOR distance 00258 OverlayKey delta = key ^ getThisNode().getKey(); 00259 00260 // find first subinteger that is not zero... 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 }
| void Kademlia::routingDeinit | ( | ) | [private] |
Definition at line 225 of file Kademlia.cc.
Referenced by joinOverlay(), and ~Kademlia().
00226 { 00227 // delete buckets 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 }
| void Kademlia::routingInit | ( | ) | [private] |
Definition at line 209 of file Kademlia.cc.
Referenced by joinOverlay().
00210 { 00211 // set join state 00212 state = INIT; 00213 00214 setOverlayReady(false); 00215 00216 // setup comparator 00217 comparator = new KeyDistanceComparator<KeyXorMetric>( thisNode.getKey() ); 00218 00219 siblingTable->setComparator(comparator); 00220 00221 updateTooltip(); 00222 BUCKET_CONSISTENCY(routingInit: end); 00223 }
| bool Kademlia::routingRemove | ( | const OverlayKey & | key | ) | [private] |
Removes a node from the routing table.
| key | Key of the Node |
Definition at line 431 of file Kademlia.cc.
00432 { 00433 return routingTimeout(key, true); 00434 }
| bool Kademlia::routingTimeout | ( | const OverlayKey & | key, | |
| bool | immediately = false | |||
| ) | [private] |
Removes a node after a number of timeouts or immediately if immediately is true (behaves like routingRemove).
| key | Node's key to remove | |
| immediately | If true, the node is removed immediately |
Definition at line 436 of file Kademlia.cc.
Referenced by handleRpcTimeout(), refillSiblingTable(), and routingRemove().
00437 { 00438 BUCKET_CONSISTENCY(routingTimeout: start); 00439 // key unspecified? yes -> ignore 00440 if (key.isUnspecified()) 00441 return false; 00442 00443 // bucket index 00444 KademliaBucket::iterator i; 00445 00446 /* check if the node is one of the siblings -----------------------------*/ 00447 if ((i = siblingTable->findIterator(key)) != siblingTable->end()) { 00448 00449 i->incStaleCount(); 00450 00451 if (i->getStaleCount() > maxStaleCount || immediately) { 00452 // remove from sibling table 00453 NodeHandle oldSibling = *i; 00454 siblingTable->erase(i); 00455 00456 if (siblingTable->size() < (uint32_t)getMaxNumSiblings()) { 00457 // no new replacement sibling 00458 deleteOverlayNeighborArrow(oldSibling); 00459 callUpdate(oldSibling, false); 00460 } else if (comparator->compare(oldSibling.getKey(), 00461 siblingTable->at(getMaxNumSiblings() - 1).getKey()) < 0) { 00462 // failed sibling was replaced by next closest node in siblingTable 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 // lost last sibling? 00474 if (siblingTable->size() == 0) { 00475 join(); 00476 return true; 00477 } 00478 00479 BUCKET_CONSISTENCY(routingTimeout: is sibling); 00480 00481 // try to refill with new closest contact 00482 refillSiblingTable(); 00483 00484 return true; 00485 } 00486 } 00487 00488 /* check if node is already in a bucket ---------------------------------*/ 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 // remove from routing table 00498 bucket->erase(i); 00499 } 00500 if (it != replacementCache.end()) { 00501 routingAdd(it->second, true); 00502 nodesReplaced++; 00503 //EV << "node replaced" << endl; 00504 } 00505 BUCKET_CONSISTENCY(routingTimeout: is in bucket); 00506 return true; 00507 } 00508 BUCKET_CONSISTENCY(routingTimeout: end); 00509 return false; 00510 }
| void Kademlia::setBucketUsage | ( | const OverlayKey & | key | ) | [private] |
Definition at line 542 of file Kademlia.cc.
Referenced by handleBucketRefreshTimerExpired(), handleRpcResponse(), and handleRpcTimeout().
00543 { 00544 KademliaBucket* bucket = routingBucket(key, true); 00545 00546 if (bucket) 00547 bucket->setLastUsage(simTime()); 00548 00549 /* 00550 if (!siblingTable->size() || ((siblingTable->back().getKey() ^ thisNode.getKey()) >= 00551 (key ^ thisNode.getKey()))) 00552 siblingTable->setLastUsage(simTime()); 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 }
| void Kademlia::updateTooltip | ( | ) | [protected] |
updates information shown in GUI
Definition at line 994 of file Kademlia.cc.
Referenced by handleFailedNode(), routingAdd(), routingInit(), and routingTimeout().
00995 { 00996 if (ev.isGUI()) { 00997 std::stringstream ttString; 00998 00999 // show our nodeId in a tooltip 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 }
friend class KademliaLookupListener [friend] |
uint32_t Kademlia::b [protected] |
Definition at line 47 of file Kademlia.h.
Referenced by handleBucketRefreshTimerExpired(), initializeOverlay(), and routingBucketIndex().
uint32_t Kademlia::bucketRefreshCount [private] |
Definition at line 116 of file Kademlia.h.
Referenced by finishOverlay(), handleBucketRefreshTimerExpired(), and initializeOverlay().
cMessage* Kademlia::bucketRefreshTimer [protected] |
Definition at line 59 of file Kademlia.h.
Referenced by handleBucketRefreshTimerExpired(), handleRpcResponse(), handleTimerEvent(), initializeOverlay(), joinOverlay(), lookupFinished(), and ~Kademlia().
KeyDistanceComparator<KeyXorMetric>* Kademlia::comparator [private] |
Definition at line 120 of file Kademlia.h.
Referenced by handleFailedNode(), initializeOverlay(), Kademlia(), refillSiblingTable(), routingBucket(), routingDeinit(), routingInit(), routingTimeout(), and ~Kademlia().
bool Kademlia::exhaustiveRefresh [protected] |
Definition at line 53 of file Kademlia.h.
Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().
uint32_t Kademlia::k [protected] |
Definition at line 46 of file Kademlia.h.
Referenced by getMaxNumRedundantNodes(), initializeOverlay(), refillSiblingTable(), and routingBucket().
uint32_t Kademlia::maxStaleCount [protected] |
simtime_t Kademlia::minBucketRefreshInterval [protected] |
Definition at line 57 of file Kademlia.h.
Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().
simtime_t Kademlia::minSiblingTableRefreshInterval [protected] |
Definition at line 56 of file Kademlia.h.
Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().
uint32_t Kademlia::nodesReplaced [private] |
Definition at line 118 of file Kademlia.h.
Referenced by finishOverlay(), initializeOverlay(), and routingTimeout().
int Kademlia::numBuckets [private] |
bool Kademlia::pingNewSiblings [protected] |
std::map<NodeHandle, NodeHandle> Kademlia::replacementCache [private] |
Definition at line 126 of file Kademlia.h.
Referenced by handleRpcResponse(), handleRpcTimeout(), routingAdd(), routingTimeout(), and ~Kademlia().
std::vector<KademliaBucket*> Kademlia::routingTable [private] |
Definition at line 123 of file Kademlia.h.
Referenced by findNode(), handleBucketRefreshTimerExpired(), handleFailedNode(), initializeOverlay(), refillSiblingTable(), routingBucket(), and routingDeinit().
uint32_t Kademlia::s [protected] |
Definition at line 48 of file Kademlia.h.
Referenced by getMaxNumSiblings(), handleBucketRefreshTimerExpired(), and initializeOverlay().
KademliaBucket* Kademlia::siblingTable [private] |
Definition at line 122 of file Kademlia.h.
Referenced by findNode(), handleBucketRefreshTimerExpired(), handleFailedNode(), initializeOverlay(), isSiblingFor(), Kademlia(), lookupFinished(), refillSiblingTable(), routingAdd(), routingDeinit(), routingInit(), routingTimeout(), setBucketUsage(), updateTooltip(), and ~Kademlia().
uint32_t Kademlia::siblingTableRefreshCount [private] |
Definition at line 117 of file Kademlia.h.
Referenced by finishOverlay(), handleBucketRefreshTimerExpired(), and initializeOverlay().
1.5.8