Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Private Attributes | Friends

Kademlia Class Reference

Kademlia overlay module. More...

#include <Kademlia.h>

Inheritance diagram for Kademlia:
BaseOverlay ProxListener BaseRpc BaseTcpSupport TopologyVis RpcListener

List of all members.

Public Member Functions

 Kademlia ()
 ~Kademlia ()
void initializeOverlay (int stage)
void finishOverlay ()
void joinOverlay ()
bool isSiblingFor (const NodeHandle &node, const OverlayKey &key, int numSiblings, bool *err)
int getMaxNumSiblings ()
int getMaxNumRedundantNodes ()
void handleTimerEvent (cMessage *msg)
bool handleRpcCall (BaseCallMessage *msg)
void handleUDPMessage (BaseOverlayMessage *msg)
virtual void proxCallback (const TransportAddress &node, int rpcId, cPolymorphic *contextPointer, Prox prox)

Protected Member Functions

NodeVectorfindNode (const OverlayKey &key, int numRedundantNodes, int numSiblings, BaseOverlayMessage *msg)
void handleRpcResponse (BaseResponseMessage *msg, cPolymorphic *context, int rpcId, simtime_t rtt)
void handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, cPolymorphic *context, int rpcId, const OverlayKey &destKey)
void handleBucketRefreshTimerExpired ()
 handle a expired bucket refresh timer
OverlayKey distance (const OverlayKey &x, const OverlayKey &y, bool useAlternative=false) const
void updateTooltip ()
 updates information shown in GUI
virtual void lookupFinished (bool isValid)
virtual void handleNodeGracefulLeaveNotification ()

Protected Attributes

uint32_t k
uint32_t b
uint32_t s
uint32_t maxStaleCount
bool exhaustiveRefresh
bool pingNewSiblings
bool secureMaintenance
 if true, ping not authenticated nodes before adding them to a bucket
bool newMaintenance
bool enableReplacementCache
bool replacementCachePing
uint replacementCandidates
int siblingRefreshNodes
int bucketRefreshNodes
bool activePing
bool proximityRouting
bool proximityNeighborSelection
bool altRecMode
simtime_t minSiblingTableRefreshInterval
simtime_t minBucketRefreshInterval
simtime_t siblingPingInterval
cMessage * bucketRefreshTimer
cMessage * siblingPingTimer

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.
KademliaBucketroutingBucket (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, bool maintenanceLookup=false)
 Adds a node to 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 sendSiblingFindNodeCall (const TransportAddress &dest)
void setBucketUsage (const OverlayKey &key)
bool recursiveRoutingHook (const TransportAddress &dest, BaseRouteMessage *msg)
bool handleFailedNode (const TransportAddress &failed)

Private Attributes

uint32_t bucketRefreshCount
uint32_t siblingTableRefreshCount
uint32_t nodesReplaced
KeyDistanceComparator
< KeyXorMetric > * 
comparator
KademliaBucketsiblingTable
std::vector< KademliaBucket * > routingTable
int numBuckets

Friends

class KademliaLookupListener

Detailed Description

Kademlia overlay module.

Author:
Sebastian Mies, Ingmar Baumgart, Bernhard Heep

This class implements the Kademlia protocol described in P. Maymounkov and D. Mazières, "Kademlia: A Peer-to-Peer Information System Based on the XOR Metric", Lecture Notes in Computer Science, Peer-to-Peer Systems: First International Workshop (IPTPS 2002). Revised Papers, 2002, 2429/2002, 53-65

The recursive routing mode (R/Kademlia) is described in B. Heep, "R/Kademlia: Recursive and Topology-aware Overlay Routing", Proceedings of the Australasian Telecommunication Networks and Applications Conference 2010 (ATNAC 2010), Auckland, New Zealand, 2010

The security extensions (S/Kademlia) are described in I. Baumgart and S. Mies, "S/Kademlia: A Practicable Approach Towards Secure Key-Based Routing", Proceedings of the 13th International Conference on Parallel and Distributed Systems (ICPADS '07), Hsinchu, Taiwan, 2007

Definition at line 61 of file Kademlia.h.


Constructor & Destructor Documentation

Kademlia::Kademlia (  ) 

Definition at line 161 of file Kademlia.cc.

{
    siblingTable = NULL;
    comparator = NULL;
    bucketRefreshTimer = NULL;
    siblingPingTimer = NULL;
}

Kademlia::~Kademlia (  ) 

Definition at line 169 of file Kademlia.cc.

{
    routingDeinit();

    delete siblingTable;
    delete comparator;
    cancelAndDelete(bucketRefreshTimer);
    cancelAndDelete(siblingPingTimer);
}


Member Function Documentation

OverlayKey Kademlia::distance ( const OverlayKey x,
const OverlayKey y,
bool  useAlternative = false 
) const [protected]

Definition at line 1378 of file Kademlia.cc.

{
    if (!useAlternative) return x^y; // KeyXorMetric().distance(x, y);
    return KeyPrefixMetric().distance(x, y);
}

NodeVector * Kademlia::findNode ( const OverlayKey key,
int  numRedundantNodes,
int  numSiblings,
BaseOverlayMessage msg 
) [protected]

Definition at line 928 of file Kademlia.cc.

Referenced by recursiveRoutingHook().

{
    if (numSiblings > getMaxNumSiblings()) {
        opp_error("(Kademlia::findNode()) numRedundantNodes or numSiblings "
                  "too big!");
    }

#if 0
    if (numRedundantNodes < 2) {
        throw cRuntimeError("Kademlia::findNode(): For Kademlia "
                                "redundantNodes must be at least 2 "
                                "and lookupMerge should be true!");
    }
#endif

    // create temporary comparator
    KeyDistanceComparator<KeyXorMetric>* comp =
        new KeyDistanceComparator<KeyXorMetric>( key );

    // select result set size
    bool err;
    int resultSize;

    if (numSiblings < 0) {
        // exhaustive iterative doesn't care about siblings
        resultSize = numRedundantNodes;
    } else {
        resultSize = isSiblingFor(thisNode, key, numSiblings, &err) ?
                (numSiblings ? numSiblings : 1) : numRedundantNodes;
    }
    assert(numSiblings || numRedundantNodes);

    NodeVector* result = new NodeVector(resultSize, comp);

    if (siblingTable->isEmpty()) {
        result->add(thisNode);
        delete comp;
        return result;
    }

    // R/Kademlia: in recursive mode just speed up route messages //TODO iterative PR
    bool returnProxNodes = false;
    if (proximityRouting) {
        if (msg &&
            (!dynamic_cast<FindNodeCall*>(msg->getEncapsulatedPacket()) &&
             !dynamic_cast<FindNodeCall*>(msg))) {
            returnProxNodes = true;
        }
    }

    ProxNodeVector* resultProx = NULL;
    KademliaPRComparator* compProx = NULL;
    if (returnProxNodes) {
        compProx = new KademliaPRComparator(key);
        resultProx = new ProxNodeVector(resultSize, NULL, NULL, compProx, 0, resultSize);
    }

    // add items from buckets
    int index;
    int mainIndex = routingBucketIndex(key);
    int startIndex = routingBucketIndex(key, true);
    int endIndex = routingBucketIndex(siblingTable->back().getKey());

    // add nodes from best fitting bucket
    if (mainIndex != -1) {
        KademliaBucket* bucket = routingTable[mainIndex];
        if (bucket != NULL && bucket->size()) {
            for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
                result->add(*i);
                if (returnProxNodes)
                    resultProx->add(*i);
                //EV << "Kademlia::findNode(): Adding "
                //   << *i << " from bucket " << mainIndex << endl;
            }
        }
    }

    // add most fitting buckets
    if (startIndex >= endIndex || !result->isFull()) {
        for (index = startIndex; index >= endIndex; --index) {
            // add bucket to result vector
            if (index == mainIndex) continue;
            KademliaBucket* bucket = routingTable[index];
            if (bucket != NULL && bucket->size()) {
                for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
                    result->add(*i);
                    if (returnProxNodes)
                        resultProx->add(*i);//std::make_pair(*i, i->getRtt()));
                    //EV << "Kademlia::routingGetClosestNodes(): Adding "
                    //   << *i << " from bucket " << index << endl;
                }
            }
        }

        // add nodes from sibling table
        for (KademliaBucket::iterator i = siblingTable->begin();
             i != siblingTable->end(); i++) {
            result->add(*i);
            if (returnProxNodes)
                resultProx->add(*i);
        }
        // add local node
        result->add(thisNode);
        if (returnProxNodes) {
            KademliaBucketEntry temp = thisNode;
            if (!result->size() || (*result)[0] == thisNode) {
                temp.setProx(Prox::PROX_SELF);
                resultProx->add(temp);
            } else {
                temp.setProx(Prox::PROX_UNKNOWN);
                resultProx->add(temp);
            }
        }
    }

    // add more distant buckets
    for (index = mainIndex + 1; !result->isFull() && index < numBuckets;
         ++index) {
        // add bucket to result vector
        KademliaBucket* bucket = routingTable[index];
        if (bucket != NULL && bucket->size()) {
            for (KademliaBucket::iterator i=bucket->begin(); i!=bucket->end(); i++) {
                result->add(*i);
                if (returnProxNodes)
                    resultProx->add(*i);
                //EV << "[Kademlia::routingGetClosestNodes()]\n"
                //   << "    Adding " << *i << " from bucket " << index
                //   << endl;
            }
        }
    }

    if (returnProxNodes) {
        result->clear();
        for (uint32_t i = 0; i < resultProx->size(); ++i) {
            result->push_back((*resultProx)[i]/*.first*/);
        }
        delete compProx;
        delete resultProx;
    }

    delete comp;

    return result;
}

void Kademlia::finishOverlay (  ) 

Definition at line 179 of file Kademlia.cc.

{
    simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
    if (time < GlobalStatistics::MIN_MEASURED) return;

    globalStatistics->addStdDev("Kademlia: Nodes replaced in buckets/s",
                                nodesReplaced / time);
    globalStatistics->addStdDev("Kademlia: Bucket Refreshes/s",
                                bucketRefreshCount / time);
    globalStatistics->addStdDev("Kademlia: Sibling Table Refreshes/s",
                                siblingTableRefreshCount / time);
}

int Kademlia::getMaxNumRedundantNodes (  ) 

Definition at line 279 of file Kademlia.cc.

{
    return k;
}

int Kademlia::getMaxNumSiblings (  ) 

Definition at line 274 of file Kademlia.cc.

Referenced by findNode(), isSiblingFor(), sendSiblingFindNodeCall(), and setBucketUsage().

{
    return s;
}

void Kademlia::handleBucketRefreshTimerExpired (  )  [protected]

handle a expired bucket refresh timer

Definition at line 1280 of file Kademlia.cc.

Referenced by handleTimerEvent().

{
    // refresh buckets
    if (state != READY || (((simTime() - siblingTable->getLastUsage()) >
                            minSiblingTableRefreshInterval))) {
        // R/Kademlia
        if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
            defaultRoutingType == FULL_RECURSIVE_ROUTING ||
            defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
            //TODO real exhaustive-recursive lookup
            createLookup()->lookup(getThisNode().getKey() + OverlayKey::ONE,
                                   0, hopCountMax, 0,
                                   new KademliaLookupListener(this));
        } else if (exhaustiveRefresh) {
            //TODO config shit
            int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
            iterativeLookupConfig.redundantNodes = siblingRefreshNodes;
            createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
                 getThisNode().getKey(), siblingRefreshNodes,
                 hopCountMax, 0, new KademliaLookupListener(this));
            iterativeLookupConfig.redundantNodes = baseRedundantNodes;
        } else if (newMaintenance) {
            //for (KademliaBucket::iterator i = siblingTable->begin();
            //     i != siblingTable->end(); i++) {

            //    sendSiblingFindNodeCall(*i);
            //}
            if (siblingTable->size()) {
                sendSiblingFindNodeCall(siblingTable->at(intuniform(0,siblingTable->size()-1)));
            }
            state = READY;
            setOverlayReady(true);
        } else {
            createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
                                   new KademliaLookupListener(this));
        }
        siblingTable->setLastUsage(simTime());
        ++siblingTableRefreshCount;
    }

    if (state == READY) {
        if (siblingTable->size()) {
            // get bit index of most significant digit that differs
            // from our next sibling's key to prevent us from refreshing
            // buckets, which can't contain any nodes
            int32_t diff = OverlayKey::getLength() - b*(getThisNode().getKey().
                sharedPrefixLength(siblingTable->front().getKey(), b) + 1);
            int bucketsRefreshedPerTask = 0;
            for (int32_t i = OverlayKey::getLength() - b; i >= diff; i -=b ) {
                for (int32_t d=0; d < ((1 << b) - 1); d++) {
                    int32_t index = (i / b) * ((1 << b) - 1) + d;
                    if (index < 0) continue;
                    if ((routingTable[index] == NULL) ||
                        ((simTime() - routingTable[index]->getLastUsage()) >
                        minBucketRefreshInterval)) {

                        OverlayKey refreshKey =
                            getThisNode().getKey() ^ (OverlayKey(d+1) << i);

                        // R/Kademlia
                        if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
                            defaultRoutingType == FULL_RECURSIVE_ROUTING ||
                            defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
                            //TODO real exhaustive-recursive lookup
                            createLookup()->lookup(refreshKey, 0,
                                                   hopCountMax, 0,
                                                   new KademliaLookupListener(this));
                        } else if (exhaustiveRefresh) {
                            //TODO config shit
                            int baseRedundantNodes = iterativeLookupConfig.redundantNodes;
                            iterativeLookupConfig.redundantNodes = bucketRefreshNodes;
                            createLookup(EXHAUSTIVE_ITERATIVE_ROUTING)->lookup(
                                refreshKey, bucketRefreshNodes, hopCountMax,
                                0, new KademliaLookupListener(this));
                            iterativeLookupConfig.redundantNodes = baseRedundantNodes;
                        } else {
                            createLookup()->lookup(refreshKey, s, hopCountMax, 0,
                                             new KademliaLookupListener(this));
                        }

                        ++bucketsRefreshedPerTask;
                        ++bucketRefreshCount;
                        setBucketUsage(refreshKey);
                    }
                }
            }
            RECORD_STATS(globalStatistics->recordOutVector(
                                   "Kademlia: Buckets Refreshed Per Task",
                                   bucketsRefreshedPerTask));
        }
        // schedule next bucket refresh process
        cancelEvent(bucketRefreshTimer);
        scheduleAt(simTime() + (std::min(minSiblingTableRefreshInterval,
                        minBucketRefreshInterval) / 10.0), bucketRefreshTimer);
    }
}

bool Kademlia::handleFailedNode ( const TransportAddress failed  )  [private]

Definition at line 805 of file Kademlia.cc.

{
    assert(!failed.isUnspecified());

    KademliaBucket::iterator i;
    // check sibling table
    for (i = siblingTable->begin(); i != siblingTable->end(); ++i) {
        if (failed == *i) break;
    }

    if (i != siblingTable->end()) {
        // remove from sibling table
        NodeHandle oldSibling = *i;
        siblingTable->erase(i);

        // call update() for removed sibling
        deleteOverlayNeighborArrow(oldSibling);
        callUpdate(oldSibling, false);

        updateTooltip();

        // try to refill with new closest contact
        refillSiblingTable();
    } else {
        // check buckets
        uint32_t m;
        for (m = 0; m < routingTable.size(); ++m) {
            if (routingTable[m] != NULL) {
                for (i = routingTable[m]->begin(); i != routingTable[m]->end();
                     ++i) {
                    if (failed == *i) {
                        // remove from routing table
                        routingTable[m]->erase(i);
                        return (siblingTable->size() != 0);
                    }
                }
            }
        }
    }
    return (siblingTable->size() != 0);
}

void Kademlia::handleNodeGracefulLeaveNotification (  )  [protected, virtual]

Definition at line 790 of file Kademlia.cc.

{
    // send failed node call to all siblings
    FailedNodeCall* call = new FailedNodeCall();
    call->setFailedNode(getThisNode());
    call->setBitLength(FAILEDNODECALL_L(call));
    for (KademliaBucket::iterator i = siblingTable->begin();
         i != siblingTable->end(); i++) {
        countFailedNodeCall(call);
        sendUdpRpcCall(*i, call->dup());
    }

    delete call;
}

bool Kademlia::handleRpcCall ( BaseCallMessage msg  ) 

Definition at line 1116 of file Kademlia.cc.

{
    bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
    RPC_SWITCH_START(msg)
    RPC_ON_CALL(Ping) {
        // add active node
        OverlayCtrlInfo* ctrlInfo =
            check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
        routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
        break;
    }
    RPC_ON_CALL(FindNode)
    {
        // add active node
        OverlayCtrlInfo* ctrlInfo =
            check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo());
        routingAdd(ctrlInfo->getSrcRoute(), true, MAXTIME, maintenanceLookup);
        break;
    }
    RPC_SWITCH_END()
    return false;
}

void Kademlia::handleRpcResponse ( BaseResponseMessage msg,
cPolymorphic *  context,
int  rpcId,
simtime_t  rtt 
) [protected]

Definition at line 1140 of file Kademlia.cc.

{
    bool maintenanceLookup = (msg->getStatType() == MAINTENANCE_STAT);
    OverlayCtrlInfo* ctrlInfo =
        dynamic_cast<OverlayCtrlInfo*>(msg->getControlInfo());
    NodeHandle srcRoute = (ctrlInfo ? ctrlInfo->getSrcRoute()
                                    : msg->getSrcNode());

    RPC_SWITCH_START(msg)
        RPC_ON_RESPONSE(Ping) {
            if (state == INIT) {
                // schedule bucket refresh timer
                cancelEvent(bucketRefreshTimer);
                scheduleAt(simTime(), bucketRefreshTimer);
                cancelEvent(siblingPingTimer);
                scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
                state = JOIN;
            }
        }
        RPC_ON_RESPONSE(FindNode)
        {
            if (state == INIT) {
                state = JOIN;

                // bootstrap node is trustworthy: add all nodes immediately
                routingAdd(srcRoute, true, rtt, maintenanceLookup);
                for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
                    routingAdd(_FindNodeResponse->getClosestNodes(i), true,
                               MAXTIME-1, maintenanceLookup);

                if (newMaintenance) {
                    createLookup()->lookup(getThisNode().getKey(), s, hopCountMax, 0,
                                       new KademliaLookupListener(this));
                } else {
                    // schedule bucket refresh timer
                    cancelEvent(bucketRefreshTimer);
                    scheduleAt(simTime(), bucketRefreshTimer);
                    cancelEvent(siblingPingTimer);
                    scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
                }

                break;
            }

            // add active node
            if (defaultRoutingType == SEMI_RECURSIVE_ROUTING ||
                defaultRoutingType == FULL_RECURSIVE_ROUTING ||
                defaultRoutingType == RECURSIVE_SOURCE_ROUTING) {
                rtt = MAXTIME;
            }
            setBucketUsage(srcRoute.getKey());

            // add inactive nodes
            for (uint32_t i=0; i<_FindNodeResponse->getClosestNodesArraySize(); i++)
                routingAdd(_FindNodeResponse->getClosestNodes(i), false,
                           MAXTIME, maintenanceLookup);
            break;
        }
    RPC_SWITCH_END()

    // add node that responded
    routingAdd(srcRoute, true, rtt, maintenanceLookup);
}

void Kademlia::handleRpcTimeout ( BaseCallMessage msg,
const TransportAddress dest,
cPolymorphic *  context,
int  rpcId,
const OverlayKey destKey 
) [protected]

Definition at line 1207 of file Kademlia.cc.

{
    if (dest.isUnspecified()) return;
    try {
        RPC_SWITCH_START(msg)
        RPC_ON_CALL(Ping) {
            if (state == INIT) {
                joinOverlay();
                return;
            }

            const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
            routingTimeout(handle.getKey());
            break;
        }
        RPC_ON_CALL(FindNode) {
            if (state == INIT) {
                joinOverlay();
                return;
            }

            const NodeHandle& handle = dynamic_cast<const NodeHandle&>(dest);
            routingTimeout(handle.getKey());
            setBucketUsage(handle.getKey());
            break;
        }
        RPC_SWITCH_END()
    } catch (...) {
        EV << "[Kademlia:handleRpcTimout() @ " << thisNode.getIp()
           << " (" << thisNode.getKey().toString(16) << ")]\n"
           << "    ERROR: RPC timeout without key ("
           << msg << " -> " << dest << ")" << endl;
        return;
    }
}

void Kademlia::handleTimerEvent ( cMessage *  msg  ) 

Definition at line 1078 of file Kademlia.cc.

{
    if (msg == bucketRefreshTimer) {
        handleBucketRefreshTimerExpired();
    } else if (msg == siblingPingTimer) {
        if (siblingPingInterval == 0) {
            return;
        }

        for (KademliaBucket::iterator i = siblingTable->begin();
             i != siblingTable->end(); i++) {
            pingNode(*i);
        }
        scheduleAt(simTime() + siblingPingInterval, msg);
    }
}

void Kademlia::handleUDPMessage ( BaseOverlayMessage msg  ) 

Definition at line 1096 of file Kademlia.cc.

{
    // only used for recursive Kademlia
    OverlayCtrlInfo* ctrlInfo =
            check_and_cast<OverlayCtrlInfo*>(msg->removeControlInfo());
    KademliaRoutingInfoMessage* kadRoutingInfoMsg =
            check_and_cast<KademliaRoutingInfoMessage*>(msg);

    routingAdd(kadRoutingInfoMsg->getSrcNode(), true);

    for (uint32_t i = 0; i < kadRoutingInfoMsg->getNextHopsArraySize(); i++) {
        routingAdd(kadRoutingInfoMsg->getNextHops(i),
                   kadRoutingInfoMsg->getNextHops(i).getIsAlive());
    }

    delete ctrlInfo;
    delete msg;
}

void Kademlia::initializeOverlay ( int  stage  ) 

Definition at line 94 of file Kademlia.cc.

{
    if (stage != MIN_STAGE_OVERLAY)
        return;

    // Kademlia provides KBR services
    kbr = true;

    // setup kademlia parameters
    minSiblingTableRefreshInterval = par("minSiblingTableRefreshInterval");
    minBucketRefreshInterval = par("minBucketRefreshInterval");
    siblingPingInterval = par("siblingPingInterval");
    exhaustiveRefresh = par("exhaustiveRefresh");
    maxStaleCount = par("maxStaleCount");
    pingNewSiblings = par("pingNewSiblings");
    enableReplacementCache = par("enableReplacementCache");
    replacementCachePing = par("replacementCachePing");
    replacementCandidates = par("replacementCandidates");
    secureMaintenance = par("secureMaintenance");
    newMaintenance = par("newMaintenance");

    // R/Kademlia
    activePing = par("activePing");
    proximityRouting = par("proximityRouting");
    proximityNeighborSelection = par("proximityNeighborSelection");
    altRecMode = recordRoute = par("altRecMode");

    k = par("k");
    b = par("b");
    s = par("s");

    siblingRefreshNodes = par("siblingRefreshNodes");

    if (siblingRefreshNodes <= 0) {
        siblingRefreshNodes = 5 * s;
    }

    bucketRefreshNodes = par("bucketRefreshNodes");

    if (bucketRefreshNodes <= 0) {
        bucketRefreshNodes = iterativeLookupConfig.redundantNodes;
    }

    // calculate number of buckets: ( (2^b)-1 ) * ( keylength / b )
    numBuckets = ((1L << b) - 1L) * (OverlayKey::getLength() / b);

    // init routing and sibling table
    siblingTable = new KademliaBucket(s * 5, NULL);

    // initialize pointers
    routingTable.assign(numBuckets, (KademliaBucket*)NULL);

    WATCH_VECTOR(*siblingTable);
    WATCH_VECTOR(routingTable);

    // self-message
    bucketRefreshTimer = new cMessage("bucketRefreshTimer");
    siblingPingTimer = new cMessage("siblingPingTimer");

    // statistics
    bucketRefreshCount = 0;
    siblingTableRefreshCount = 0;
    nodesReplaced = 0;

    comparator = NULL;
}

bool Kademlia::isSiblingFor ( const NodeHandle node,
const OverlayKey key,
int  numSiblings,
bool *  err 
)

Definition at line 714 of file Kademlia.cc.

Referenced by findNode().

{
    if (key.isUnspecified())
        error("Kademlia::isSiblingFor(): key is unspecified!");

    if (state != READY) {
        EV << "[Kademlia::isSiblingFor()] @ "
           << thisNode.getIp()
           << " (" << thisNode.getKey().toString(16) << ")]\n"
           << "    state != READY"
           << endl;
        *err = true;
        return false;
    }

    if (numSiblings > getMaxNumSiblings()) {
        opp_error("Kademlia::isSiblingFor(): numSiblings too big!");
    }

    // set default number of siblings to consider
    if (numSiblings == -1) {
        numSiblings = getMaxNumSiblings();
    }

    if (numSiblings == 0) {
        *err = false;
        return (node.getKey() == key);
    }

    if (siblingTable->size() < (uint)numSiblings) {
        *err = false;
        return true;
    }

    if (siblingTable->isFull() &&
        ((thisNode.getKey() ^ key) >
         (thisNode.getKey() ^ siblingTable->back().getKey()))) {
        EV << "[Kademlia::isSiblingFor()] @ "
           << thisNode.getIp()
           << " (" << thisNode.getKey().toString(16) << ")]\n"
           << "    Not sure if I am sibling for " << key << " !\n"
           << "    (" << key << " is not closer to me than "
           << siblingTable->back().getKey() << ")"
           << endl;
        *err = true;
        return false;
    }

    KeyDistanceComparator<KeyXorMetric>* comp =
        new KeyDistanceComparator<KeyXorMetric>(key);

    // create result vector
    NodeVector* result = new NodeVector(numSiblings, comp);

    for (KademliaBucket::iterator i=siblingTable->begin();
         i != siblingTable->end(); i++) {
        result->add( *i);
    }

    // add local node
    result->add(thisNode);

    *err = false;
    delete comp;

    if (result->contains(node.getKey())) {
        delete result;
        return true;
    } else {
        delete result;
        assert(!(numSiblings == 1 && key == node.getKey()));
        return false;
    }
}

void Kademlia::joinOverlay (  ) 

Definition at line 203 of file Kademlia.cc.

Referenced by handleRpcTimeout(), and lookupFinished().

{
    // remove current node handle from the bootstrap list
    if (!thisNode.getKey().isUnspecified()) {
        bootstrapList->removeBootstrapNode(thisNode);
    }

    // initialize routing
    routingDeinit();
    routingInit();

    TransportAddress handle = bootstrapList->getBootstrapNode();

    if (!handle.isUnspecified()) {
        if (secureMaintenance) {
            sendSiblingFindNodeCall(handle);
        } else {
            // ping the bootstrap node to start bootstrapping
            pingNode(handle);
        }
    } else {
        // we're the only node in the network
        state = READY;
        setOverlayReady(true);

        // schedule bucket refresh timer
        cancelEvent(bucketRefreshTimer);
        scheduleAt(simTime(), bucketRefreshTimer);
        cancelEvent(siblingPingTimer);
        scheduleAt(simTime() + siblingPingInterval, siblingPingTimer);
    }
}

void Kademlia::lookupFinished ( bool  isValid  )  [protected, virtual]

Definition at line 1259 of file Kademlia.cc.

Referenced by KademliaLookupListener::lookupFinished().

{
    if (state == JOIN) {
        cancelEvent(bucketRefreshTimer);

        if (siblingTable->size() == 0) {
            // initial lookup failed - get new bootstrap node
            joinOverlay();
            return;
        }

        scheduleAt(simTime(), bucketRefreshTimer);

        if (!newMaintenance) {
            state = READY;
            setOverlayReady(true);
        }
    }
}

void Kademlia::proxCallback ( const TransportAddress node,
int  rpcId,
cPolymorphic *  contextPointer,
Prox  prox 
) [virtual]

Implements ProxListener.

Definition at line 1247 of file Kademlia.cc.

{
    Enter_Method_Silent();

    if (prox != Prox::PROX_TIMEOUT) {
        routingAdd((const NodeHandle&)node, true, prox.proximity);
    } else {
        routingTimeout(((const NodeHandle&)node).getKey());
    }
}

bool Kademlia::recursiveRoutingHook ( const TransportAddress dest,
BaseRouteMessage msg 
) [private]

Definition at line 848 of file Kademlia.cc.

{
    if (msg->getSrcNode() != thisNode) {
        if (!msg->getDestKey().isUnspecified()) {
            routingAdd(msg->getSrcNode(), true);

            if (altRecMode && dest != thisNode) return true;

            NodeVector* nextHops = findNode(msg->getDestKey(), /*recursiveLookupConfig.redundantNodes*/ k, s, msg);
            KademliaRoutingInfoMessage* kadRoutingInfoMsg =
                new KademliaRoutingInfoMessage();

            kadRoutingInfoMsg->setSrcNode(thisNode);
            kadRoutingInfoMsg->setDestKey(msg->getDestKey());
            kadRoutingInfoMsg->setNextHopsArraySize(nextHops->size());
            kadRoutingInfoMsg->setName("KadRoutingInfoMsg");
            for (uint32_t i = 0; i < nextHops->size(); i++) {
                kadRoutingInfoMsg->setNextHops(i, (*nextHops)[i]);
                if (thisNode == kadRoutingInfoMsg->getNextHops(i)) {
                    kadRoutingInfoMsg->getNextHops(i).setIsAlive(true);
                }
            }
            kadRoutingInfoMsg->setBitLength(KADEMLIAROUTINGINFO_L(kadRoutingInfoMsg));

            delete nextHops;

            if (!altRecMode) {
                sendMessageToUDP(msg->getSrcNode(), kadRoutingInfoMsg);
            } else {
                // alternative maintenance mode
                std::vector<TransportAddress> sourceRoute;
                for (int i = msg->getVisitedHopsArraySize() - 1/*2*/; i >= 0; i--) {
                    //TODO remove loops
                    sourceRoute.push_back(msg->getVisitedHops(i));
                }
                //sourceRoute.push_back(msg->getSrcNode());
                sendToKey(OverlayKey::UNSPECIFIED_KEY, kadRoutingInfoMsg, 0,
                          sourceRoute, NO_OVERLAY_ROUTING);
            }
            //TODO should be sent after baseroutemsg
        } else if (altRecMode &&
                   dynamic_cast<KademliaRoutingInfoMessage*>(msg->
                           getEncapsulatedPacket())) {
            // alternative mode: infoMsg on its way back
            KademliaRoutingInfoMessage* infoMsg =
                static_cast<KademliaRoutingInfoMessage*>(msg->decapsulate());
            NodeVector* nextHops = findNode(infoMsg->getDestKey(), k, s, msg);

            // merge vectors
            KeyDistanceComparator<KeyXorMetric> comp(infoMsg->getDestKey());
            MarkedNodeVector temp(UINT16_MAX, &comp);

            for (uint32_t i = 0; i < nextHops->size(); i++) {
                temp.push_back((*nextHops)[i]);
            }
            delete nextHops;

            for (uint32_t i = 0; i < infoMsg->getNextHopsArraySize(); i++) {
                routingAdd(infoMsg->getNextHops(i),
                           infoMsg->getNextHops(i).getIsAlive());
                temp.add(infoMsg->getNextHops(i));
            }

            infoMsg->setNextHopsArraySize(temp.size());
            for (uint32_t i = 0; i < temp.size(); ++i) {
                infoMsg->setNextHops(i, temp[i]);
                if (thisNode == infoMsg->getNextHops(i)) {
                    infoMsg->getNextHops(i).setIsAlive(true);
                }
            }
            infoMsg->setBitLength(KADEMLIAROUTINGINFO_L(infoMsg));

            msg->encapsulate(infoMsg);
        }
    }
    return true;
}

void Kademlia::refillSiblingTable (  )  [private]

Definition at line 659 of file Kademlia.cc.

Referenced by handleFailedNode(), and routingTimeout().

{
    if (siblingTable->size() == 0 ||
        siblingTable->isFull())
        return;

    int index = routingBucketIndex(siblingTable->back().getKey()) - 1;
    assert(index > 0);

    while ((routingTable[index] == NULL ||
            routingTable[index]->empty()) &&
            index < (int)(OverlayKey::getLength() - 1)) {
        index++;
    }
    if (index < (int)OverlayKey::getLength() &&
            routingTable[index] != NULL && routingTable[index]->size()) {

        KademliaBucket sortedBucket(k, comparator);
        for (uint32_t i = 0; i < routingTable[index]->size(); ++i) {
            sortedBucket.add(routingTable[index]->at(i));
        }

        siblingTable->add(sortedBucket.front());

        // call update() for new sibling
        if (!secureMaintenance) {
            showOverlayNeighborArrow(sortedBucket.front(), false,
                                     "m=m,50,100,50,100;ls=green,1");
            callUpdate(sortedBucket.front(), true);
        }

        // remove node from bucket
        routingTable[index]->erase(routingTable[index]->
              findIterator(sortedBucket.front().getKey()));
        assert(siblingTable->isFull());
        BUCKET_CONSISTENCY(routingTimeout: end refillSiblingTable());
    }
}

bool Kademlia::routingAdd ( const NodeHandle handle,
bool  isAlive,
simtime_t  rtt = MAXTIME,
bool  maintenanceLookup = false 
) [private]

Adds a node to the routing table.

Parameters:
handle handle to add
isAlive true, if it is known that the node is alive
rtt measured round-trip-time to node
maintenanceLookup true, if this node was learned from a maintenance lookup
Returns:
true, if the node was known or has been added

maintenanceLookup ||

Definition at line 319 of file Kademlia.cc.

Referenced by handleRpcCall(), handleRpcResponse(), handleUDPMessage(), proxCallback(), recursiveRoutingHook(), and routingTimeout().

{
    BUCKET_CONSISTENCY(routingAdd: start);
    // never add unspecified node handles
    if (handle.isUnspecified() || handle.getKey() == getThisNode().getKey()) {
        return false;
    }


    // bucket index
    KademliaBucket::iterator i;
    bool result = false;
    bool authenticated = (isAlive && (rtt != MAXTIME));

    bool needsRtt = (activePing && ((rtt == MAXTIME) ? true : false));

    // convert node handle
    KademliaBucketEntry kadHandle = handle;
    kadHandle.setRtt(rtt);
    kadHandle.setLastSeen(simTime());

    /* check if node is already a sibling -----------------------------------*/
    if ((i = siblingTable->findIterator(handle.getKey()))
         != siblingTable->end()) {
        // not alive? -> do not change routing information
        if (isAlive) {
            if (!secureMaintenance || authenticated) {
                if (kadHandle.getRtt() == MAXTIME) {
                    kadHandle.setRtt(i->getRtt());
                }
                // refresh sibling
                (*i) = kadHandle;
            } else {
                if (maintenanceLookup) {
                    return false;
                }

                if ((i->getIp() != handle.getIp()) ||
                    (i->getPort() != handle.getPort())) {
                    // sibling could have changed transport address
                    // ping new address for authentication
                    pingNode(handle);
                    return false;
                }
            }
        }
        BUCKET_CONSISTENCY(routingAdd: node is sibling);
        return true;
    }

    /* check if node is already in a bucket ---------------------------------*/
    KademliaBucket* bucket = routingBucket(handle.getKey(), false);
    if (bucket != NULL && (i = bucket->findIterator(handle.getKey() ) )
            != bucket->end() ) {
        // not alive? -> do not change routing information
        if (isAlive) {
            if (!secureMaintenance || authenticated) {
                if (kadHandle.getRtt() == MAXTIME) {
                    kadHandle.setRtt(i->getRtt());
                }

                // R/Kademlia
                if (needsRtt && (kadHandle.getRtt() == MAXTIME)) {
                    Prox prox =
                        neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
                                               this, NULL);
                    if (prox != Prox::PROX_SELF &&
                        prox != Prox::PROX_UNKNOWN &&
                        prox != Prox::PROX_TIMEOUT) {
                        kadHandle.setProx(prox);
                        //routingAdd(handle, true, prox.proximity);//ctrlInfo->getSrcRoute() //TODO
                    } /*else if (prox == Prox::PROX_TIMEOUT) {
                        // remove from bucket
                        bucket->erase(i);
                        return false;
                    }*/ //TODO inform NC that node is alive
                    else {
                        return false;
                    }
                }

                // remove old handle
                bucket->erase(i);
                // re-add to tail
                bucket->push_back(kadHandle);
            } else {
                if (maintenanceLookup) {
                    return false;
                }

                if ((i->getIp() != handle.getIp()) ||
                    (i->getPort() != handle.getPort())) {
                    // sibling could have changed transport address
                    // ping new address for authentication
                    pingNode(handle);
                    return false;
                }
            }
        }

        BUCKET_CONSISTENCY(routingAdd: node is in bucket);
        return true;
    }

    /* check if node can be added to the sibling list -----------------------*/
    if (siblingTable->isAddable(handle) ) {
        if (secureMaintenance && !authenticated) {
            if (!maintenanceLookup || (isAlive && (rtt == MAXTIME))) {
                // received a FindNodeCall or PingCall from a potential sibling
                // or new nodes from a FindNodeResponse app lookup
                pingNode(handle);
            } else if (newMaintenance) {
                // new node from sibling table refresh
                //sendSiblingFindNodeCall(handle);
                pingNode(handle);
            }
            return false;
        }

        // ping new siblings
        if (pingNewSiblings && !isAlive) {
            pingNode(handle);
        }

        // R/Kademlia
        else if (needsRtt) {
            // old version: pingNode(), now:
            Prox prox =
                    neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
                                           this, NULL);
            if (prox != Prox::PROX_SELF &&
                prox != Prox::PROX_UNKNOWN &&
                prox != Prox::PROX_TIMEOUT) {
                kadHandle.setProx(prox);
            } else if (prox == Prox::PROX_TIMEOUT) {
                // do not put handle into sibling table
                return false;
            }
        }

        bool finished = false;
        int siblingPos = -1;

        // check if sibling list is full so a handle is preemted from the list
        if (siblingTable->isFull()) {
            // get handle thats about to be preempted
            KademliaBucketEntry oldHandle = siblingTable->back();
            assert(oldHandle.getKey() != kadHandle.getKey());

            // add handle to the sibling list
            siblingPos = siblingTable->add(kadHandle);

            // change, so that the preempted handle is added to a bucket
            kadHandle = oldHandle;

            // call update() for removed sibling
            if (!secureMaintenance) {
                deleteOverlayNeighborArrow(oldHandle);
                callUpdate(oldHandle, false);
            }

            // return always true, since the handle has been added
            result = true;
        } else {
            // simply add the handle and stop
            siblingPos = siblingTable->add(kadHandle);

            // don't need to add kadHandle also to regular buckets
            finished = true;
        }
        assert(siblingPos > -1);

        updateTooltip();

        // call update() for new sibling
        showOverlayNeighborArrow(handle, false,
                                 "m=m,50,100,50,100;ls=green,1");
        callUpdate(handle, true);

        if (finished) {
            BUCKET_CONSISTENCY(routingAdd: node is now sibling);
            return true;
        }
    }

    /* add node to the appropriate bucket, if not full ---------------------*/
    bucket = routingBucket(kadHandle.getKey(), true);
    if (!bucket->isFull()) {
        if (secureMaintenance && !authenticated) {
            if ((isAlive && (rtt == MAXTIME))) {
                // received a FindNodeCall or PingCall from a potential new bucket entry
                // or new nodes from a FindNodeReponse app lookup
                // optimization: don't send a ping for nodes from FindNodeResponse for app lookups
                pingNode(kadHandle);
            }
            return false;
        }

        EV << "[Kademlia::routingAdd()]\n"
           << "    Adding new node " << kadHandle
           << " to bucket " << routingBucketIndex(kadHandle.getKey())
           << endl;

        // PNS
        if (needsRtt || proximityNeighborSelection) {
             //pingNode(handle, -1, 0, NULL, NULL, NULL, -1, UDP_TRANSPORT, false);
             Prox prox =
                 neighborCache->getProx(handle, NEIGHBORCACHE_DEFAULT, -1,
                                        this, NULL);
             if (prox != Prox::PROX_SELF &&
                 prox != Prox::PROX_UNKNOWN &&
                 prox != Prox::PROX_TIMEOUT) {
                 //routingAdd(handle, true, prox.proximity);//ctrlInfo->getSrcRoute() //TODO
                 kadHandle.setProx(prox);
             }
         }

        bucket->push_back(kadHandle);
        result = true;
    } else if (isAlive) {
        //PNS node replacement
        if (proximityNeighborSelection &&
            kadHandle.getProx() != Prox::PROX_UNKNOWN) {
            KademliaBucket::iterator kickHim, it;
            kickHim = it = bucket->begin();
            ++it;
            while (it != bucket->end()) {
                if (it->getRtt() > kickHim->getRtt()) {
                    kickHim = it;
                }
                ++it;
            }
            if (kickHim->getRtt() > kadHandle.getRtt()) {
                KademliaBucketEntry temp = *kickHim;
                bucket->erase(kickHim);
                bucket->push_back(kadHandle);
                kadHandle = temp;
            }
        }

        if (enableReplacementCache && (!secureMaintenance || authenticated)) {
            bucket->replacementCache.push_front(kadHandle);
            if (bucket->replacementCache.size() > replacementCandidates) {
                bucket->replacementCache.pop_back();
            }

            if (replacementCachePing) {
                KademliaBucket::iterator it = bucket->begin();
                while (it != bucket->end() && (it->getPingSent() == true)) {
                    it++;
                }
                if (it != bucket->end()) {
                    pingNode(*it);
                    it->setPingSent(true);
                }
            }
        }
    }

    // PNS
    else if (proximityNeighborSelection) {
        neighborCache->getProx(handle, NEIGHBORCACHE_QUERY, -1, this, NULL);
        //pingNode(handle);
    }

    BUCKET_CONSISTENCY(routingAdd: end);
    return result;
}

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.

Parameters:
key The key of the node
ensure If true, the bucket allocation is ensured
Returns:
Bucket* The Bucket

Definition at line 303 of file Kademlia.cc.

Referenced by routingAdd(), routingTimeout(), and setBucketUsage().

{
    // get bucket index
    int num = routingBucketIndex(key);
    if (num < 0)
        return NULL;

    // get bucket and allocate if necessary
    KademliaBucket* bucket = routingTable[ num ];
    if (bucket == NULL && ensure)
        bucket = routingTable[ num ] = new KademliaBucket( k, comparator );

    // return bucket
    return bucket;
}

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.

Parameters:
key The key of the node
firstOnLayer If true bucket with smallest index on same layer is returned
Returns:
int The index of the bucket

Definition at line 284 of file Kademlia.cc.

Referenced by findNode(), refillSiblingTable(), routingAdd(), and routingBucket().

{
    // calculate XOR distance
    OverlayKey delta = key ^ getThisNode().getKey();

    // find first subinteger that is not zero...
    int i;
    for (i = key.getLength() - b; i >= 0 && delta.getBitRange(i, b) == 0;
         i -= b);

    if (i < 0)
        return -1;

    if (!firstOnLayer)
        return (i / b) * ((1 << b) - 1) + (delta.getBitRange(i, b) - 1);
    else
        return (i / b) * ((1 << b) - 1) + (pow(2, b) - 2);
}

void Kademlia::routingDeinit (  )  [private]

Definition at line 254 of file Kademlia.cc.

Referenced by joinOverlay(), and ~Kademlia().

{
    // delete buckets
    for (uint32_t i = 0; i < routingTable.size(); i++) {
        if (routingTable[i] != NULL) {
            delete routingTable[i];
            routingTable[i] = NULL;
        }
    }

    if (siblingTable != NULL) {
        siblingTable->clear();
    }

    if (comparator != NULL) {
        delete comparator;
        comparator = NULL;
    }
}

void Kademlia::routingInit (  )  [private]

Definition at line 238 of file Kademlia.cc.

Referenced by joinOverlay().

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).

Parameters:
key Node's key to remove
immediately If true, the node is removed immediately
Returns:
true, if the node has been removed

Definition at line 589 of file Kademlia.cc.

Referenced by handleRpcTimeout(), proxCallback(), and refillSiblingTable().

{
    BUCKET_CONSISTENCY(routingTimeout: start);
    // key unspecified? yes -> ignore
    if (key.isUnspecified())
        return false;

    // bucket index
    KademliaBucket::iterator i;

    /* check if the node is one of the siblings -----------------------------*/
    if ((i = siblingTable->findIterator(key)) != siblingTable->end()) {

        i->incStaleCount();
        i->setPingSent(false);

        if (i->getStaleCount() > maxStaleCount || immediately) {
            // remove from sibling table
            NodeHandle oldSibling = *i;
            siblingTable->erase(i);

            // lost last sibling?
            if (siblingTable->size() == 0) {
                join();
                return true;
            }

            BUCKET_CONSISTENCY(routingTimeout: is sibling);

            // try to refill with new closest contact
            refillSiblingTable();

            // call update() for removed sibling
            deleteOverlayNeighborArrow(oldSibling);
            callUpdate(oldSibling, false);

            updateTooltip();

            return true;
        }
    }

    /* check if node is already in a bucket ---------------------------------*/
    KademliaBucket* bucket = routingBucket(key, false);
    if (bucket != NULL && (i = bucket->findIterator(key) ) != bucket->end() ) {

        i->incStaleCount();
        i->setPingSent(false);

        if (i->getStaleCount() > maxStaleCount || immediately) {
            // remove from routing table
            bucket->erase(i);

            if (enableReplacementCache) {
                if (bucket->replacementCache.size()) {
                    routingAdd(bucket->replacementCache.front(), true,
                               bucket->replacementCache.front().getRtt());
                    bucket->replacementCache.pop_front();
                    nodesReplaced++;
                }
            }
        }

        BUCKET_CONSISTENCY(routingTimeout: is in bucket);
        return true;
    }
    BUCKET_CONSISTENCY(routingTimeout: end);
    return false;
}

void Kademlia::sendSiblingFindNodeCall ( const TransportAddress dest  )  [private]

Definition at line 192 of file Kademlia.cc.

Referenced by handleBucketRefreshTimerExpired(), and joinOverlay().

{
    FindNodeCall* call = new FindNodeCall("FindNodeCall");
    call->setExhaustiveIterative(true);
    call->setLookupKey(thisNode.getKey());
    call->setNumRedundantNodes(siblingRefreshNodes);
    call->setNumSiblings(getMaxNumSiblings());
    call->setBitLength(FINDNODECALL_L(call));
    sendUdpRpcCall(dest, call);
}

void Kademlia::setBucketUsage ( const OverlayKey key  )  [private]

Definition at line 698 of file Kademlia.cc.

Referenced by handleBucketRefreshTimerExpired(), handleRpcResponse(), and handleRpcTimeout().

{
    KademliaBucket* bucket = routingBucket(key, true);

    if (bucket) {
        bucket->setLastUsage(simTime());
    }

    if ((siblingTable->size() < (uint32_t)getMaxNumSiblings())
        || ((siblingTable->at(getMaxNumSiblings() - 1).getKey() ^ thisNode.getKey())
                >= (key ^ thisNode.getKey()))) {
        siblingTable->setLastUsage(simTime());
    }

}

void Kademlia::updateTooltip (  )  [protected]

updates information shown in GUI

Definition at line 1386 of file Kademlia.cc.

Referenced by handleFailedNode(), routingAdd(), routingInit(), and routingTimeout().

{
    if (ev.isGUI()) {
        std::stringstream ttString;

        // show our nodeId in a tooltip
        ttString << "This: " << thisNode << endl << "Siblings: "
                 << siblingTable->size();

        getParentModule()->getParentModule()->getDisplayString().
        setTagArg("tt", 0, ttString.str().c_str());
        getParentModule()->getDisplayString().
        setTagArg("tt", 0, ttString.str().c_str());
        getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
    }
}


Friends And Related Function Documentation

friend class KademliaLookupListener [friend]

Definition at line 155 of file Kademlia.h.

Referenced by handleBucketRefreshTimerExpired(), and handleRpcResponse().


Member Data Documentation

bool Kademlia::activePing [protected]

Definition at line 84 of file Kademlia.h.

Referenced by initializeOverlay(), and routingAdd().

bool Kademlia::altRecMode [protected]

Definition at line 87 of file Kademlia.h.

Referenced by initializeOverlay(), and recursiveRoutingHook().

uint32_t Kademlia::b [protected]
uint32_t Kademlia::bucketRefreshCount [private]

Definition at line 159 of file Kademlia.h.

Referenced by finishOverlay(), handleBucketRefreshTimerExpired(), and initializeOverlay().

Definition at line 81 of file Kademlia.h.

Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().

Definition at line 77 of file Kademlia.h.

Referenced by initializeOverlay(), routingAdd(), and routingTimeout().

bool Kademlia::exhaustiveRefresh [protected]

Definition at line 72 of file Kademlia.h.

Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().

uint32_t Kademlia::maxStaleCount [protected]

Definition at line 69 of file Kademlia.h.

Referenced by initializeOverlay(), and routingTimeout().

simtime_t Kademlia::minBucketRefreshInterval [protected]

Definition at line 90 of file Kademlia.h.

Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().

Definition at line 89 of file Kademlia.h.

Referenced by handleBucketRefreshTimerExpired(), and initializeOverlay().

uint32_t Kademlia::nodesReplaced [private]

Definition at line 161 of file Kademlia.h.

Referenced by finishOverlay(), initializeOverlay(), and routingTimeout().

int Kademlia::numBuckets [private]

Definition at line 167 of file Kademlia.h.

Referenced by findNode(), and initializeOverlay().

bool Kademlia::pingNewSiblings [protected]

Definition at line 73 of file Kademlia.h.

Referenced by initializeOverlay(), and routingAdd().

Definition at line 86 of file Kademlia.h.

Referenced by initializeOverlay(), and routingAdd().

bool Kademlia::proximityRouting [protected]

Definition at line 85 of file Kademlia.h.

Referenced by findNode(), and initializeOverlay().

Definition at line 78 of file Kademlia.h.

Referenced by initializeOverlay(), and routingAdd().

Definition at line 79 of file Kademlia.h.

Referenced by initializeOverlay(), and routingAdd().

bool Kademlia::secureMaintenance [protected]

if true, ping not authenticated nodes before adding them to a bucket

Definition at line 74 of file Kademlia.h.

Referenced by initializeOverlay(), joinOverlay(), refillSiblingTable(), and routingAdd().

simtime_t Kademlia::siblingPingInterval [protected]

Definition at line 91 of file Kademlia.h.

Referenced by handleRpcResponse(), handleTimerEvent(), initializeOverlay(), and joinOverlay().


The documentation for this class was generated from the following files: