#include <Kademlia.h>
Public Member Functions | |
~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) |
Processes "timer" self-messages. | |
void | handleUDPMessage (BaseOverlayMessage *msg) |
Processes messages from underlay. | |
bool | handleRpc (BaseCallMessage *msg) |
Processes Remote-Procedure-Call invokation 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 stabilize 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 | |
uint | k |
uint | b |
uint | s |
uint | r |
uint | maxStaleCount |
bool | pingNewSiblings |
bool | activePing |
simtime_t | minSiblingTableRefreshInterval |
simtime_t | minBucketRefreshInterval |
cMessage * | bucketRefreshTimer |
uint | nodesReplaced |
Private Member Functions | |
void | routingInit () |
void | routingDeinit () |
int | routingBucketIndex (const OverlayKey &key) |
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 | forwardMessageRecursive (const TransportAddress &dest, BaseRouteMessage *msg) |
Hook for forwarded message in recursive lookup mode. | |
bool | handleFailedNode (const TransportAddress &failed) |
Handles a failed node. | |
Private Attributes | |
KeyDistanceComparator < KeyXorMetric > * | comparator |
KademliaBucket * | siblingTable |
std::vector< KademliaBucket * > | routingTable |
int | numBuckets |
std::map< NodeHandle, NodeHandle > | replacementCache |
Friends | |
class | KademliaLookupListener |
Kademlia::~Kademlia | ( | ) |
00115 { 00116 routingDeinit(); 00117 00118 replacementCache.clear(); 00119 delete comparator; 00120 cancelAndDelete(bucketRefreshTimer); 00121 }
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.
00086 { 00087 if (stage != MIN_STAGE_OVERLAY) 00088 return; 00089 00090 // Kademlia provides KBR services 00091 kbr = true; 00092 00093 // setup kademlia parameters 00094 minSiblingTableRefreshInterval = par("minSiblingTableRefreshInterval"); 00095 minBucketRefreshInterval = par("minBucketRefreshInterval"); 00096 maxStaleCount = par("maxStaleCount"); 00097 pingNewSiblings = par("pingNewSiblings"); 00098 00099 activePing = par("activePing"); 00100 00101 k = par("k"); 00102 b = par("b"); 00103 s = par("s"); 00104 00105 // self-message 00106 bucketRefreshTimer = new cMessage("bucketRefreshTimer"); 00107 00108 nodesReplaced = 0; 00109 00110 comparator = NULL; 00111 siblingTable = NULL; 00112 }
void Kademlia::finishOverlay | ( | ) | [virtual] |
collects statistical data in derived class
Reimplemented from BaseOverlay.
00124 { 00125 // cancel timer 00126 cancelEvent(bucketRefreshTimer); 00127 00128 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime); 00129 if(time == 0) return; 00130 00131 globalStatistics->addStdDev("Kademlia: Nodes replaced in buckets/s", 00132 nodesReplaced / time); 00133 }
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.
Referenced by handleRpcTimeout(), and routingTimeout().
00136 { 00137 // remove current node handle from the bootstrap list 00138 if (!thisNode.key.isUnspecified()) { 00139 bootstrapList->removeBootstrapNode(thisNode); 00140 } 00141 00142 // initialize routing 00143 routingDeinit(); 00144 routingInit(); 00145 00146 const NodeHandle& handle = bootstrapList->getBootstrapNode(); 00147 00148 if (!handle.isUnspecified()) { 00149 // ping the bootstrap node to start bootstrapping 00150 pingNode(handle); 00151 //std::cout << thisNode << " bootstrapping via " << handle << std::endl; 00152 /* 00153 FindNodeCall* findNodeCall = new FindNodeCall(); 00154 findNodeCall->setLookupKey(handle.getKey()); 00155 findNodeCall->setSrcNode(getThisNode()); 00156 findNodeCall->setNumRedundantNodes(getMaxNumRedundantNodes()); 00157 findNodeCall->setNumSiblings(getMaxNumSiblings()); 00158 findNodeCall->setLength(FINDNODECALL_L(call)); 00159 00160 RECORD_STATS(numFindNodeSent++; 00161 bytesFindNodeSent += findNodeCall->byteLength()); 00162 00163 sendUdpRpcCall(handle, findNodeCall); 00164 */ 00165 } else { 00166 // we're the only node in the network 00167 state = READY; 00168 setOverlayReady(true); 00169 00170 // schedule bucket refresh timer 00171 cancelEvent(bucketRefreshTimer); 00172 scheduleAt(simulation.simTime(), bucketRefreshTimer); 00173 } 00174 }
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.
Referenced by findNode().
00537 { 00538 if (key.isUnspecified()) 00539 error("Kademlia::isSiblingFor(): key is unspecified!"); 00540 00541 if (state != READY) { 00542 *err = true; 00543 return false; 00544 } 00545 00546 if (numSiblings > getMaxNumSiblings()) { 00547 opp_error("Kademlia::isSiblingFor(): numSiblings too big!"); 00548 } 00549 00550 // set default number of siblings to consider 00551 if (numSiblings == -1) { 00552 numSiblings = getMaxNumSiblings(); 00553 } 00554 00555 if (numSiblings == 0) { 00556 *err = false; 00557 return (node.getKey() == key); 00558 } 00559 00560 if (siblingTable->isEmpty()) { 00561 *err = false; 00562 return true; 00563 } 00564 00565 if ((thisNode.key ^ key) > (thisNode.key ^ siblingTable->back().key)) { 00566 *err = true; 00567 return false; 00568 } 00569 00570 KeyDistanceComparator<KeyXorMetric>* comp = 00571 new KeyDistanceComparator<KeyXorMetric>(key); 00572 00573 // create result vector 00574 NodeVector* result = new NodeVector(numSiblings, comp); 00575 00576 for (KademliaBucket::iterator i=siblingTable->begin(); 00577 i != siblingTable->end(); i++) { 00578 result->add( *i); 00579 } 00580 00581 // add local node 00582 result->add(thisNode); 00583 00584 *err = false; 00585 delete comp; 00586 00587 if (result->contains(node.key)) { 00588 delete result; 00589 return true; 00590 } else { 00591 delete result; 00592 return false; 00593 } 00594 }
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.
Referenced by findNode(), handleFailedNode(), isSiblingFor(), routingAdd(), and routingTimeout().
00228 { 00229 return s; 00230 }
int Kademlia::getMaxNumRedundantNodes | ( | ) | [virtual] |
Query the maximum number of redundant next hop nodes that are returned by findNode().
Reimplemented from BaseOverlay.
Referenced by findNode().
00233 { 00234 return k; 00235 }
void Kademlia::handleTimerEvent | ( | cMessage * | msg | ) | [virtual] |
Processes "timer" self-messages.
msg | A self-message |
Reimplemented from BaseOverlay.
00723 { 00724 if (msg == bucketRefreshTimer) { 00725 handleBucketRefreshTimerExpired(); 00726 } 00727 }
void Kademlia::handleUDPMessage | ( | BaseOverlayMessage * | msg | ) | [virtual] |
Processes messages from underlay.
msg | Message from UDP |
Reimplemented from BaseOverlay.
00730 { 00731 OverlayCtrlInfo* ctrlInfo = 00732 check_and_cast<OverlayCtrlInfo*>(msg->removeControlInfo()); 00733 KademliaRoutingInfoMessage* kadRoutingInfoMsg = check_and_cast< 00734 KademliaRoutingInfoMessage*>(msg); 00735 00736 routingAdd(kadRoutingInfoMsg->getSrcNode(), true); 00737 00738 for (uint i = 0; i < kadRoutingInfoMsg->getNextHopsArraySize(); i++) { 00739 routingAdd(kadRoutingInfoMsg->getNextHops(i), false); 00740 } 00741 00742 delete ctrlInfo; 00743 delete msg; 00744 }
bool Kademlia::handleRpc | ( | BaseCallMessage * | msg | ) | [virtual] |
Processes Remote-Procedure-Call invokation messages.
This method should be overloaded when the overlay provides RPC functionality.
Reimplemented from BaseRpc.
00748 { 00749 RPC_SWITCH_START( msg ) 00750 RPC_ON_CALL( Ping ) { 00751 // add active node 00752 routingAdd( _PingCall->getSrcNode(), true ); 00753 break; 00754 } 00755 RPC_ON_CALL(FindNode) 00756 { 00757 // add active node 00758 routingAdd(_FindNodeCall->getSrcNode(), true); 00759 break; 00760 } 00761 RPC_SWITCH_END( ) 00762 return false; 00763 }
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.
00656 { 00657 if ((numRedundantNodes > getMaxNumRedundantNodes()) || (numSiblings 00658 > getMaxNumSiblings())) { 00659 00660 opp_error("(Kademlia::findNode()) numRedundantNodes or numSiblings " 00661 "too big!"); 00662 } 00663 00664 if (numRedundantNodes < 2) { 00665 throw new cRuntimeError("Kademlia::findNode(): For Kademlia " 00666 "redundantNodes must be at least 2 " 00667 "and lookupMerge should be true!"); 00668 } 00669 00670 // create temporary comparator 00671 KeyDistanceComparator<KeyXorMetric>* comp = 00672 new KeyDistanceComparator<KeyXorMetric>( key ); 00673 00674 // select result set size 00675 bool err; 00676 int resultSize = isSiblingFor(thisNode, key, numSiblings, &err) ? 00677 (numSiblings ? numSiblings : 1) : numRedundantNodes; 00678 00679 assert(numSiblings || numRedundantNodes); 00680 00681 NodeVector* result = new NodeVector(resultSize, comp); 00682 00683 NodeRttVector* resultProx = NULL; 00684 KeyDistanceComparator<KeyPrefixMetric>* compProx = NULL; 00685 00686 // add items from buckets 00687 int mainIndex = routingBucketIndex(key); 00688 00689 for (int i = 1; !result->isFull() && i < numBuckets * 3; i++) { 00690 int index = mainIndex + (((i & 1) == 1) ? -1 : 1) * (i / 2); 00691 if (index < 0 || index >= numBuckets) 00692 continue; 00693 00694 // add bucket to result vector 00695 KademliaBucket* bucket = routingTable[index]; 00696 if (bucket!=NULL) { 00697 for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) { 00698 result->add(*i); 00699 } 00700 } 00701 } 00702 00703 // add nodes from sibling table 00704 for (KademliaBucket::iterator i = siblingTable->begin(); 00705 i != siblingTable->end(); i++) { 00706 result->add(*i); 00707 } 00708 00709 // add local node 00710 result->add(thisNode); 00711 00712 delete comp; 00713 delete compProx; 00714 delete resultProx; 00715 00716 return result; 00717 }
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.
00769 { 00770 // add node that reponded 00771 routingAdd(msg->getSrcNode(), true, rtt); 00772 00773 RPC_SWITCH_START(msg) 00774 RPC_ON_RESPONSE(Ping) { 00775 if (state == INIT) { 00776 // schedule bucket refresh timer 00777 cancelEvent(bucketRefreshTimer); 00778 scheduleAt(simulation.simTime(), bucketRefreshTimer); 00779 state = JOIN; 00780 } 00781 00782 // add active node 00783 replacementCache.erase(_PingResponse->getSrcNode()); 00784 //routingAdd(_PingResponse->getSrcNode(), true , rtt); 00785 } 00786 RPC_ON_RESPONSE(FindNode) 00787 { 00788 // add active node 00789 if (defaultRoutingType == SEMI_RECURSIVE_ROUTING || 00790 defaultRoutingType == FULL_RECURSIVE_ROUTING || 00791 defaultRoutingType == RECURSIVE_SOURCE_ROUTING) 00792 rtt = MAXTIME; 00793 //routingAdd(_FindNodeResponse->getSrcNode(), true, rtt); 00794 setBucketUsage(_FindNodeResponse->getSrcNode().key); 00795 00796 // add inactive nodes 00797 for (uint i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++) 00798 routingAdd(_FindNodeResponse->getClosestNodes(i), false); 00799 break; 00800 } 00801 RPC_SWITCH_END() 00802 }
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.
00809 { 00810 if (dest.isUnspecified()) return; 00811 00812 const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest); 00813 00814 RPC_SWITCH_START(msg) 00815 if (state == JOIN) { 00816 joinOverlay(); 00817 } 00818 RPC_ON_CALL(Ping) { 00819 routingTimeout(handle.key); 00820 00821 // remove node from replacementCache 00822 std::map<NodeHandle, NodeHandle>::iterator it 00823 = replacementCache.find(handle); 00824 if (it != replacementCache.end()) { 00825 replacementCache.erase(it); 00826 } 00827 00828 break; 00829 } 00830 RPC_ON_CALL(FindNode) { 00831 routingTimeout(handle.key); 00832 setBucketUsage(handle.key); 00833 break; 00834 } 00835 RPC_SWITCH_END() 00836 }
void Kademlia::handleBucketRefreshTimerExpired | ( | ) | [protected] |
handle a expired stabilize timer
handle a expired bucket refresh timer
Referenced by handleTimerEvent().
00877 { 00878 // refresh buckets 00879 if (state != READY || (((simTime() - siblingTable->getLastUsage()) > 00880 minSiblingTableRefreshInterval))) 00881 //std::cout << thisNode << ": lookup" << std::endl; 00882 createLookup()->lookup(getThisNode().getKey() + 00883 OverlayKey::ONE, 0, 0, 0, 00884 new KademliaLookupListener(this)); 00885 00886 if (state == READY && siblingTable->size()) { 00887 uint diff = OverlayKey::getLength() - getThisNode().getKey(). 00888 sharedPrefixLength(siblingTable->front().key); 00889 for (uint i = OverlayKey::getLength() - 1; i >= (diff - 1); i--) { 00890 if ((routingTable[i] == NULL) || 00891 ((simTime() - routingTable[i]->getLastUsage()) > 00892 minBucketRefreshInterval)) { 00893 //EV << i << "bla"; 00894 createLookup()->lookup(getThisNode().getKey() ^ 00895 (OverlayKey::ONE << i), 0, 0, 0, 00896 new KademliaLookupListener(this)); 00897 } 00898 } 00899 // schedule next bucket refresh process 00900 cancelEvent(bucketRefreshTimer); 00901 scheduleAt(simulation.simTime() + 00902 (min(minSiblingTableRefreshInterval, 00903 minBucketRefreshInterval) / 10.0), 00904 bucketRefreshTimer); 00905 } 00906 }
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.
void Kademlia::updateTooltip | ( | ) | [protected] |
updates information shown in GUI
Referenced by handleFailedNode(), routingAdd(), routingInit(), and routingTimeout().
00915 { 00916 if (ev.isGUI()) { 00917 std::stringstream ttString; 00918 00919 // show our nodeId in a tooltip 00920 ttString << "This: " << thisNode << endl << "Siblings: " 00921 << siblingTable->size(); 00922 00923 parentModule()->parentModule()->displayString(). 00924 setTagArg("tt", 0, ttString.str().c_str()); 00925 parentModule()->displayString(). 00926 setTagArg("tt", 0, ttString.str().c_str()); 00927 displayString().setTagArg("tt", 0, ttString.str().c_str()); 00928 } 00929 }
void Kademlia::lookupFinished | ( | bool | isValid | ) | [protected, virtual] |
Referenced by KademliaLookupListener::lookupFinished().
00839 { 00840 if (state != READY) { 00841 cancelEvent(bucketRefreshTimer); 00842 scheduleAt(simulation.simTime(), bucketRefreshTimer); 00843 00844 state = READY; 00845 setOverlayReady(true); 00846 } 00847 }
void Kademlia::routingInit | ( | ) | [private] |
Referenced by joinOverlay().
00179 { 00180 // set join state 00181 state = INIT; 00182 00183 setOverlayReady(false); 00184 00185 // setup comparator 00186 comparator = new KeyDistanceComparator<KeyXorMetric>( thisNode.getKey() ); 00187 00188 // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b ) 00189 numBuckets = ( (1L << b) - 1L ) * (OverlayKey::getLength() / b ); 00190 00191 // init routing and sibling table 00192 siblingTable = new KademliaBucket ( s * 5, comparator ); 00193 00194 // initialize pointers 00195 routingTable.assign(numBuckets, (KademliaBucket*)NULL); 00196 00197 WATCH_VECTOR(*siblingTable); 00198 WATCH_VECTOR(routingTable); 00199 00200 updateTooltip(); 00201 BUCKET_CONSISTENCY(routingInit: end); 00202 }
void Kademlia::routingDeinit | ( | ) | [private] |
Referenced by joinOverlay(), and ~Kademlia().
00205 { 00206 // delete buckets 00207 for (uint i = 0; i < routingTable.size(); i++) { 00208 if (routingTable[i] != NULL) { 00209 delete routingTable[i]; 00210 routingTable[i] = NULL; 00211 } 00212 } 00213 routingTable.clear(); 00214 00215 // clear sibling table 00216 if (siblingTable != NULL) { 00217 delete siblingTable; 00218 siblingTable = NULL; 00219 } 00220 00221 if (comparator != NULL) { 00222 delete comparator; 00223 comparator = NULL; 00224 } 00225 }
int Kademlia::routingBucketIndex | ( | const OverlayKey & | key | ) | [private] |
Returns the index of the bucket the key would reside with respect to Kademlia parameters.
key | The key of the node |
Referenced by findNode(), refillSiblingTable(), routingAdd(), and routingBucket().
00238 { 00239 // calculate XOR distance 00240 OverlayKey delta = key ^ getThisNode().getKey(); 00241 00242 // find first subinteger that is not zero... 00243 int i; 00244 for (i = key.getLength() - b; i >= 0 && delta.getBitRange(i, b) == 0; i -= b) 00245 ; 00246 if (i < 0) 00247 return -1; 00248 00249 assert((i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1) == 00250 OverlayKey::getLength() - 00251 getThisNode().getKey().sharedPrefixLength(key, b) - 1); 00252 00253 return (i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1); 00254 }
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 |
Referenced by routingAdd(), routingTimeout(), and setBucketUsage().
00257 { 00258 // get bucket index 00259 int num = routingBucketIndex(key); 00260 if (num < 0) 00261 return NULL; 00262 00263 // get bucket and allocate if necessary 00264 KademliaBucket* bucket = routingTable[ num ]; 00265 if (bucket == NULL && ensure) 00266 bucket = routingTable[ num ] = new KademliaBucket( k, comparator ); 00267 00268 // return bucket 00269 return bucket; 00270 }
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 |
Referenced by handleRpc(), handleRpcResponse(), handleUDPMessage(), and routingTimeout().
00273 { 00274 BUCKET_CONSISTENCY(routingAdd: start); 00275 // never add unspecified node handles 00276 if (handle.isUnspecified() || handle.key == getThisNode().getKey() ) 00277 return false; 00278 00279 // bucket index 00280 KademliaBucket::iterator i; 00281 bool result = false; 00282 00283 bool needsRtt = (activePing && ((rtt == MAXTIME) ? true : false)); 00284 00285 // convert node handle 00286 KademliaBucketEntry kadHandle = handle; 00287 kadHandle.setRtt(rtt); 00288 kadHandle.setLastSeen(simulation.simTime()); 00289 00290 /* check if node is already a sibling -----------------------------------*/ 00291 if ((i = siblingTable->findIterator(handle.getKey())) 00292 != siblingTable->end()) { 00293 // not alive? -> do not change routing information 00294 if (isAlive) { 00295 if (kadHandle.getRtt() != i->getRtt()) { 00296 siblingTable->setLastUpdate(simTime()); 00297 if (kadHandle.getRtt() == MAXTIME) 00298 kadHandle.setRtt(i->getRtt()); 00299 } 00300 // refresh sibling 00301 (*i) = kadHandle; 00302 } 00303 BUCKET_CONSISTENCY(routingAdd: node is sibling); 00304 return true; 00305 } 00306 00307 /* check if node is already in a bucket ---------------------------------*/ 00308 KademliaBucket* bucket = routingBucket(handle.getKey(), false); 00309 if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) ) 00310 != bucket->end() ) { 00311 // not alive? -> do not change routing information 00312 if (isAlive) { 00313 if (kadHandle.getRtt() == MAXTIME) { 00314 kadHandle.setRtt(i->getRtt()); 00315 } 00316 // remove old handle 00317 bucket->erase(i); 00318 // re-add to tail 00319 bucket->push_back(kadHandle); 00320 00321 bucket->setLastUpdate(simTime()); 00322 00323 if (needsRtt && (kadHandle.getRtt() == MAXTIME)) 00324 pingNode(handle); 00325 } 00326 BUCKET_CONSISTENCY(routingAdd: node is in bucket); 00327 return true; 00328 } 00329 00330 /* check if node can be added to the sibling list -----------------------*/ 00331 if (siblingTable->isAddable(handle) ) { 00332 00333 bool finished = false; 00334 int siblingPos = -1; 00335 00336 // check if sibling list is full so a handle is preemted from the list 00337 if (siblingTable->isFull()) { 00338 // get handle thats about to be preempted 00339 KademliaBucketEntry oldHandle = siblingTable->back(); 00340 assert(oldHandle.key != kadHandle.key); 00341 // add handle to the sibling list 00342 siblingPos = siblingTable->add(kadHandle); 00343 00344 // change, so that the preempted handle is added to a bucket 00345 kadHandle = oldHandle; 00346 00347 // return always true, since the handle has been added 00348 result = true; 00349 } else { 00350 // simply add the handle and stop 00351 siblingPos = siblingTable->add(kadHandle); 00352 00353 // don't need to add kadHandle also to regular buckets 00354 finished = true; 00355 } 00356 assert(siblingPos > -1); 00357 00358 // ping new siblings 00359 if ((pingNewSiblings && !isAlive) || needsRtt) { 00360 pingNode(handle); 00361 } 00362 00363 siblingTable->setLastUpdate(simTime()); 00364 00365 updateTooltip(); 00366 00367 // call update() for real siblings 00368 if (siblingPos < getMaxNumSiblings()) { 00369 if (siblingTable->size() > (uint)getMaxNumSiblings()) { 00370 // removed old sibling 00371 NodeHandle& removedSibling = siblingTable->at(getMaxNumSiblings()); 00372 deleteOverlayNeighborArrow(removedSibling); 00373 callUpdate(removedSibling, false); 00374 } 00375 // new sibling 00376 showOverlayNeighborArrow(handle, false, 00377 "m=m,50,100,50,100;o=green,1"); 00378 callUpdate(handle, true); 00379 } 00380 00381 if (finished) { 00382 BUCKET_CONSISTENCY(routingAdd: node is now sibling); 00383 return true; 00384 } 00385 } 00386 00387 /* add node to the appropriate bucket, if not full ---------------------*/ 00388 bucket = routingBucket(kadHandle.getKey(), true); 00389 if (!bucket->isFull()) { 00390 EV << "Kademlia::routingAdd(): Adding new node " << kadHandle 00391 << " to bucket " << routingBucketIndex(kadHandle.getKey()) << endl; 00392 bucket->push_back(kadHandle); 00393 bucket->setLastUpdate(simTime()); 00394 result = true; 00395 } else if (isAlive) { 00396 // save candidate, ping head, 00397 KademliaBucket::iterator it = bucket->begin(); 00398 while (it != bucket->end() && 00399 replacementCache.find(*it) != replacementCache.end()) { 00400 ++it; 00401 } 00402 if (it != bucket->end()) { 00403 replacementCache.insert(std::make_pair(*it, kadHandle)); 00404 pingNode(*it, -1,-1, NULL, NULL, NULL, -1, 00405 UDP_TRANSPORT, true); 00406 } 00407 } 00408 00409 if (result && needsRtt) 00410 pingNode(handle); 00411 00412 BUCKET_CONSISTENCY(routingAdd: end); 00413 return result; 00414 }
bool Kademlia::routingRemove | ( | const OverlayKey & | key | ) | [private] |
Removes a node from the routing table.
key | Key of the Node |
00417 { 00418 return routingTimeout(key, true); 00419 }
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 |
Referenced by handleRpcTimeout(), refillSiblingTable(), and routingRemove().
00422 { 00423 BUCKET_CONSISTENCY(routingTimeout: start); 00424 // key unspecified? yes -> ignore 00425 if (key.isUnspecified()) 00426 return false; 00427 00428 // bucket index 00429 KademliaBucket::iterator i; 00430 00431 /* check if the node is one of the siblings -----------------------------*/ 00432 if ((i = siblingTable->findIterator(key)) != siblingTable->end()) { 00433 00434 i->incStaleCount(); 00435 00436 if (i->getStaleCount() > maxStaleCount || immediately) { 00437 // remove from sibling table 00438 NodeHandle oldSibling = *i; 00439 siblingTable->erase(i); 00440 00441 if (siblingTable->size() < (uint)getMaxNumSiblings()) { 00442 // no new replacement sibling 00443 deleteOverlayNeighborArrow(oldSibling); 00444 callUpdate(oldSibling, false); 00445 } else if (comparator->compare(oldSibling.key, 00446 siblingTable->at(getMaxNumSiblings() - 1).key) < 0) { 00447 // failed sibling was replaced by next closest node in siblingTable 00448 deleteOverlayNeighborArrow(oldSibling); 00449 callUpdate(oldSibling, false); 00450 00451 showOverlayNeighborArrow(siblingTable->at(getMaxNumSiblings() - 1), 00452 false, "m=m,50,100,50,100;o=green,1"); 00453 callUpdate(siblingTable->at(getMaxNumSiblings() - 1), true); 00454 } 00455 00456 updateTooltip(); 00457 00458 // lost last sibling? 00459 if (siblingTable->size() == 0) { 00460 joinOverlay(); 00461 return true; 00462 } 00463 00464 BUCKET_CONSISTENCY(routingTimeout: is sibling); 00465 00466 // try to refill with new closest contact 00467 refillSiblingTable(); 00468 00469 return true; 00470 } 00471 } 00472 00473 /* check if node is already in a bucket ---------------------------------*/ 00474 KademliaBucket* bucket = routingBucket(key, false); 00475 if (bucket != NULL && (i = bucket->findIterator(key) ) != bucket->end() ) { 00476 00477 i->incStaleCount(); 00478 std::map<NodeHandle, NodeHandle>::iterator it 00479 = replacementCache.find(*i); 00480 if (i->getStaleCount() > maxStaleCount || 00481 it != replacementCache.end() || immediately) { 00482 // remove from routing table 00483 bucket->erase(i); 00484 } 00485 if (it != replacementCache.end()) { 00486 routingAdd(it->second, true); 00487 nodesReplaced++; 00488 //EV << "node replaced" << endl; 00489 } 00490 BUCKET_CONSISTENCY(routingTimeout: is in bucket); 00491 return true; 00492 } 00493 BUCKET_CONSISTENCY(routingTimeout: end); 00494 return false; 00495 }
void Kademlia::refillSiblingTable | ( | ) | [private] |
Referenced by handleFailedNode(), and routingTimeout().
00498 { 00499 if (siblingTable->size() == 0 || 00500 siblingTable->isFull()) 00501 return; 00502 00503 int index = routingBucketIndex(siblingTable->back().key) - 1; 00504 assert(index > 0); 00505 00506 while ((routingTable[index] == NULL || 00507 routingTable[index]->empty()) && 00508 index < (int)(OverlayKey::getLength() - 1)) { 00509 index++; 00510 } 00511 if (index < (int)OverlayKey::getLength() && 00512 routingTable[index] != NULL && routingTable[index]->size()) { 00513 KademliaBucket sortedBucket(k, comparator); 00514 for (uint i = 0; i < routingTable[index]->size(); ++i) 00515 sortedBucket.add(routingTable[index]->at(i)); 00516 siblingTable->add(sortedBucket.front()); 00517 // no need to callUpdate(), because s < siblingTable->size(), thus 00518 // new sibling talbe entry is no real sibling 00519 routingTable[index]-> 00520 erase(routingTable[index]-> 00521 findIterator(sortedBucket.front().key)); 00522 assert(siblingTable->isFull()); 00523 BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable()); 00524 } 00525 }
void Kademlia::setBucketUsage | ( | const OverlayKey & | key | ) | [private] |
Referenced by handleRpcResponse(), and handleRpcTimeout().
00528 { 00529 KademliaBucket* bucket = routingBucket(key, false); 00530 00531 if (bucket) 00532 bucket->setLastUsage(simTime()); 00533 }
bool Kademlia::forwardMessageRecursive | ( | const TransportAddress & | dest, | |
BaseRouteMessage * | msg | |||
) | [private, virtual] |
Hook for forwarded message in recursive lookup mode.
This hook is called just before a message is forwarded to a next hop or if the message is at its destination just before it is sent to the app. Default implementation just returns true. This hook can for example be used to detect failed nodes and call handleFailedNode() before the actual forwarding takes place.
dest | destination node | |
msg | message to send |
Reimplemented from BaseOverlay.
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.
00597 { 00598 assert(!failed.isUnspecified()); 00599 //std::cout << "Kademlia::handleFailedNode()" << std::endl; 00600 KademliaBucket::iterator i; 00601 // check sibling table 00602 for (i = siblingTable->begin(); i != siblingTable->end(); ++i) { 00603 if (failed == *i) break; 00604 } 00605 00606 if (i != siblingTable->end()) { 00607 // remove from sibling table 00608 NodeHandle oldSibling = *i; 00609 siblingTable->erase(i); 00610 00611 if (siblingTable->size() < (uint)getMaxNumSiblings()) { 00612 // no new replacement sibling 00613 deleteOverlayNeighborArrow(oldSibling); 00614 callUpdate(oldSibling, false); 00615 } else if (comparator->compare(oldSibling.key, 00616 siblingTable->at(getMaxNumSiblings() - 1).key) < 0) { 00617 // failed sibling was replaced by next closest node in siblingTable 00618 deleteOverlayNeighborArrow(oldSibling); 00619 callUpdate(oldSibling, false); 00620 00621 showOverlayNeighborArrow(siblingTable->at(getMaxNumSiblings() - 1), 00622 false, "m=m,50,100,50,100;o=green,1"); 00623 callUpdate(siblingTable->at(getMaxNumSiblings() - 1), true); 00624 } 00625 00626 updateTooltip(); 00627 00628 // try to refill with new closest contact 00629 refillSiblingTable(); 00630 } else { 00631 // check buckets 00632 uint m; 00633 for (m = 0; m < routingTable.size(); ++m) { 00634 if (routingTable[m] != NULL) { 00635 for (i = routingTable[m]->begin(); i != routingTable[m]->end(); 00636 ++i) { 00637 if (failed == *i) { 00638 // remove from routing table 00639 routingTable[m]->erase(i); 00640 return (siblingTable->size() != 0); 00641 } 00642 } 00643 } 00644 } 00645 } 00646 return (siblingTable->size() != 0); 00647 }
friend class KademliaLookupListener [friend] |
Referenced by handleBucketRefreshTimerExpired().
uint Kademlia::k [protected] |
Referenced by getMaxNumRedundantNodes(), initializeOverlay(), refillSiblingTable(), and routingBucket().
uint Kademlia::b [protected] |
Referenced by initializeOverlay(), routingBucketIndex(), and routingInit().
uint Kademlia::s [protected] |
Referenced by getMaxNumSiblings(), initializeOverlay(), and routingInit().
uint Kademlia::r [protected] |
uint Kademlia::maxStaleCount [protected] |
Referenced by initializeOverlay(), and routingTimeout().
bool Kademlia::pingNewSiblings [protected] |
Referenced by initializeOverlay(), and routingAdd().
bool Kademlia::activePing [protected] |
Referenced by initializeOverlay(), and routingAdd().
simtime_t Kademlia::minSiblingTableRefreshInterval [protected] |
Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().
simtime_t Kademlia::minBucketRefreshInterval [protected] |
Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().
cMessage* Kademlia::bucketRefreshTimer [protected] |
uint Kademlia::nodesReplaced [protected] |
Referenced by finishOverlay(), initializeOverlay(), and routingTimeout().
KeyDistanceComparator<KeyXorMetric>* Kademlia::comparator [private] |
Referenced by handleFailedNode(), initializeOverlay(), refillSiblingTable(), routingBucket(), routingDeinit(), routingInit(), routingTimeout(), and ~Kademlia().
KademliaBucket* Kademlia::siblingTable [private] |
std::vector<KademliaBucket*> Kademlia::routingTable [private] |
Referenced by findNode(), handleBucketRefreshTimerExpired(), handleFailedNode(), refillSiblingTable(), routingBucket(), routingDeinit(), and routingInit().
int Kademlia::numBuckets [private] |
Referenced by findNode(), and routingInit().
std::map<NodeHandle, NodeHandle> Kademlia::replacementCache [private] |
Referenced by handleRpcResponse(), handleRpcTimeout(), routingAdd(), routingTimeout(), and ~Kademlia().