IterativeLookup.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include <iostream>
00025 #include <assert.h>
00026 
00027 #include <UnderlayConfigurator.h>
00028 #include <LookupListener.h>
00029 #include <BaseOverlay.h>
00030 #include <GlobalStatistics.h>
00031 
00032 #include "IterativeLookup.h"
00033 
00034 using namespace std;
00035 
00036 //----------------------------------------------------------------------------
00037 
00038 LookupListener::~LookupListener()
00039 {}
00040 
00041 //----------------------------------------------------------------------------
00042 
00043 AbstractLookup::~AbstractLookup()
00044 {}
00045 
00046 std::ostream& operator<<(std::ostream& os, const LookupEntry& n)
00047 {
00048     os << "handle: " << n.handle << " source: " << n.source
00049        << " alreadyUsed: " << n.alreadyUsed;
00050 
00051     return os;
00052 };
00053 
00054 std::ostream& operator<<(std::ostream& os, const LookupVector& n)
00055 {
00056     for (LookupVector::const_iterator i=n.begin(); i !=n.end(); i++) {
00057         os << *i;
00058         if (i+1 != n.end()) {
00059             os << endl;
00060         }
00061     }
00062 
00063     return os;
00064 };
00065 
00066 //----------------------------------------------------------------------------
00067 //- Construction & Destruction -----------------------------------------------
00068 //----------------------------------------------------------------------------
00069 IterativeLookup::IterativeLookup(BaseOverlay* overlay,
00070                                  RoutingType routingType,
00071                                  const IterativeLookupConfiguration& config,
00072                                  const cPacket* findNodeExt,
00073                                  bool appLookup) :
00074 overlay(overlay),
00075 routingType(routingType),
00076 config(config),
00077 firstCallExt(NULL),
00078 finished(false),
00079 success(false),
00080 running(false),
00081 appLookup(appLookup)
00082 {
00083     if (findNodeExt) firstCallExt = static_cast<cPacket*>(findNodeExt->dup());
00084 
00085     if ((config.parallelPaths > 1) && (!config.merge)) {
00086         throw cRuntimeError("IterativeLookup::IterativeLookup(): "
00087                                 "config.merge must be enabled for "
00088                                 "using parallel paths!");
00089     }
00090 
00091     if (config.verifySiblings && (!config.merge)) {
00092         throw cRuntimeError("IterativeLookup::IterativeLookup(): "
00093                                 "config.merge must be enabled for "
00094                                 "using secure lookups!");
00095     }
00096 
00097 
00098     if (config.majoritySiblings && (!config.merge)) {
00099         throw cRuntimeError("IterativeLookup::IterativeLookup(): "
00100                                 "config.merge must be enabled for "
00101                                 "using majority decision for sibling selection!");
00102     }
00103 
00104     if (config.useAllParallelResponses && (!config.merge)) {
00105         throw cRuntimeError("IterativeLookup::IterativeLookup(): "
00106                                 "config.merge must be enabled if "
00107                                 "config.useAllParallelResponses is true!");
00108     }
00109 }
00110 
00111 IterativeLookup::~IterativeLookup()
00112 {
00113     stop();
00114     delete firstCallExt;
00115     overlay->removeLookup(this);
00116 
00117 //    std::cout << "time: " << simTime() << "deleting " << this << endl;
00118 }
00119 
00120 void IterativeLookup::abortLookup()
00121 {
00122     if (listener != NULL) {
00123         delete listener;
00124         listener = NULL;
00125     }
00126     delete this;
00127 }
00128 
00129 void IterativeLookup::start()
00130 {
00131 //    std::cout << "time: " << simTime() << " start(): node: " << overlay->getThisNode() << " this: " << this  << " key: " << key << endl;
00132 
00133     // init params
00134     successfulPaths = 0;
00135     finishedPaths   = 0;
00136     accumulatedHops = 0;
00137 
00138     // init flags
00139     finished = false;
00140     success  = false;
00141     running  = true;
00142 
00143     // init siblings vector
00144     siblings = NodeVector(numSiblings == 0 ? 1 : numSiblings, this);
00145     visited.clear();
00146     dead.clear();
00147     pinged.clear();
00148 
00149     startTime = simTime();
00150 
00151     // get local closest nodes
00152     FindNodeCall* call = createFindNodeCall(firstCallExt);
00153     NodeVector* nextHops = overlay->findNode(key, overlay->getMaxNumRedundantNodes(),
00154         (routingType == EXHAUSTIVE_ITERATIVE_ROUTING) ? -1 : numSiblings, call);
00155 
00156     bool err;
00157 
00158     setVisited(overlay->getThisNode());
00159 
00160     // if this node is new and no nodes are known -> stop lookup
00161     if (nextHops->size() == 0) {
00162         //std::cout << "IterativeLookup: No next hops known" << endl;
00163         finished = true;
00164         success = false;
00165     } else if ((numSiblings == 0)
00166             && overlay->isSiblingFor(overlay->getThisNode(),
00167                                      key, numSiblings,
00168                                      &err)) {
00169         if (overlay->getThisNode().getKey() == key) {
00170             addSibling(overlay->getThisNode(), true);
00171             success = true;
00172         } else {
00173             std::cout << "IterativeLookup: numSiblings==0 and no node with this id"
00174                       << endl;
00175             success = false;
00176         }
00177         finished = true;
00178     }
00179     // finish lookup if the key is local and siblings are needed
00180     else if (numSiblings != 0 && routingType != EXHAUSTIVE_ITERATIVE_ROUTING &&
00181              overlay->isSiblingFor(overlay->getThisNode(), key,
00182                                    numSiblings, &err)) {
00183 
00184         for (uint32_t i=0; i<nextHops->size(); i++) {
00185             addSibling(nextHops->at(i), true);
00186         }
00187 
00188         success = finished = true;
00189     }
00190 
00191     // if the key was local or belongs to one of our siblings we are finished
00192     if (finished) {
00193         // calls stop and finishes the lookup
00194         delete nextHops;
00195         delete call;
00196         delete this;
00197         return;
00198     }
00199 
00200     // extract find node extensions
00201     cPacket* findNodeExt = NULL;
00202     if (call->hasObject("findNodeExt"))
00203         findNodeExt = (cPacket*)call->removeObject("findNodeExt");
00204     delete call;
00205 
00206     // not enough nodes for all paths? -> reduce number of parallel paths
00207     if ((uint32_t)config.parallelPaths > nextHops->size()) {
00208         config.parallelPaths = nextHops->size();
00209     }
00210 
00211     // create parallel paths and distribute nodes to paths
00212     for (int i = 0; i < config.parallelPaths; i++) {
00213 
00214         // create state
00215         IterativePathLookup* pathLookup = new IterativePathLookup(this);
00216         paths.push_back(pathLookup);
00217 
00218         // populate next hops
00219         for (uint32_t k=0; (k * config.parallelPaths + i) < nextHops->size(); k++) {
00220             pathLookup->add(nextHops->at(k * config.parallelPaths + i));
00221         }
00222 
00223         // send initial rpcs
00224         pathLookup->sendRpc(config.parallelRpcs, findNodeExt);
00225     }
00226 
00227 
00228     //std::cout << "nextHops size: " << nextHops->size()
00229     //<< " numSiblings: " << numSiblings
00230     //<< " redundantNodes: " << config.redundantNodes
00231     //<< " thisNode " << overlay->getThisNode().ip
00232     //<< " nextHop " << nextHops->at(0).ip << endl;
00233 
00234     delete nextHops;
00235     delete findNodeExt;
00236 
00237     checkStop();
00238 }
00239 
00240 void IterativeLookup::stop()
00241 {
00242     // only stop if running
00243     if (!running)
00244         return;
00245 
00246     for (uint32_t i=0; i<paths.size(); i++) {
00247         success |= paths[i]->success;
00248     }
00249 
00250     // cancel pending rpcs
00251     for (RpcInfoMap::iterator i = rpcs.begin(); i != rpcs.end(); i++) {
00252 //      std::cout << "time: " << simTime()     << " node: " << overlay->thisNode          << " this: " << this << " first: " << i->first  << " nonce: " << i->second.nonce << endl;
00253         overlay->cancelRpcMessage(i->second.nonce);
00254     }
00255     rpcs.clear();
00256 
00257     // cancel pending ping rpcs
00258     for (PendingPings::iterator i = pendingPings.begin(); i != pendingPings.end(); i++) {
00259         overlay->cancelRpcMessage(i->second);
00260     }
00261     pendingPings.clear();
00262 
00263     // delete path lookups
00264     for (uint32_t i=0; i<paths.size(); i++) {
00265         delete paths[i];
00266     }
00267     paths.clear();
00268 
00269     // reset running flag
00270     running  = false;
00271     finished = true;
00272 
00273 #if 0
00274     EV << "[IterativeLookup::stop() @ " << overlay->getThisNode().getAddress()
00275                    << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00276                    << "    Lookup " << (isValid() ? "succeeded\n" : "failed\n")
00277                    << "    (" << successfulPaths << " successful paths)\n"
00278                    << "    (" << finishedPaths << " finished paths)"
00279                    << endl;
00280 #endif
00281 
00282     // inform listener
00283     if (listener != NULL) {
00284         listener->lookupFinished(this);
00285         listener = NULL;
00286     }
00287 }
00288 
00289 inline void IterativeLookup::checkStop()
00290 {
00291     bool finishLookup = false;
00292 
00293     if (config.majoritySiblings && (numSiblings > 0) &&
00294             finishedPaths == (uint32_t)config.parallelPaths) {
00295         if (majoritySiblings.size() <= (uint)numSiblings) {
00296             // TODO: better check that all nodes have sent the same siblings
00297             MajoritySiblings::iterator it;
00298             for (it = majoritySiblings.begin(); it != majoritySiblings.end(); it++) {
00299                 siblings.add(*it);
00300             }
00301             success = true;
00302             finishLookup = true;
00303         }
00304     }
00305 
00306     // check if there are rpcs pending or lookup finished
00307     if (((successfulPaths >= 1) && (numSiblings == 0) && (siblings.size() >= 1)) ||
00308         ((finishedPaths == (uint32_t)config.parallelPaths) &&
00309                 (numSiblings > 0) && (pendingPings.size() == 0))) {
00310 
00311         for (uint32_t i=0; i<paths.size(); i++) {
00312             success |= paths[i]->success;
00313         }
00314         finishLookup = true;
00315 
00316     } else if ((rpcs.size() == 0) && (pendingPings.size() == 0)) {
00317         finishLookup = true;
00318     }
00319 
00320     if (finishLookup == true) {
00321         // TODO: should not be needed, but sometimes finishedPaths seems
00322         //       to be smaller than config.parallelPaths
00323         if (successfulPaths >= 1) {
00324             success = true;
00325         }
00326 
00327         if (success == false) {
00328             //cout << "failed: hops :" << accumulatedHops << endl;
00329         }
00330 
00331         if (success == false && retries > 0) {
00332             //      std::cout << "IterativeLookup::checkStop(): Retry..." << endl;
00333             retries--;
00334             LookupListener* oldListener = listener;
00335             listener = NULL;
00336             stop();
00337             listener = oldListener;
00338             start();
00339         } else {
00340             delete this;
00341         }
00342     }
00343 }
00344 
00345 //----------------------------------------------------------------------------
00346 //- Enhanceable methods ------------------------------------------------------
00347 //----------------------------------------------------------------------------
00348 IterativePathLookup* IterativeLookup::createPathLookup()
00349 {
00350     return new IterativePathLookup(this);
00351 }
00352 
00353 FindNodeCall* IterativeLookup::createFindNodeCall(cPacket* findNodeExt)
00354 {
00355     FindNodeCall* call = new FindNodeCall("FindNodeCall");
00356     if (appLookup) {
00357         call->setStatType(APP_LOOKUP_STAT);
00358     } else {
00359         call->setStatType(MAINTENANCE_STAT);
00360     }
00361 
00362     if (routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
00363         call->setExhaustiveIterative(true);
00364     } else {
00365         call->setExhaustiveIterative(false);
00366     }
00367 
00368     call->setLookupKey(key);
00369     call->setNumRedundantNodes(config.redundantNodes);
00370     call->setNumSiblings(numSiblings);
00371     if (routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
00372         call->setExhaustiveIterative(true);
00373     } else {
00374         call->setExhaustiveIterative(false);
00375     }
00376     call->setBitLength(FINDNODECALL_L(call));
00377 
00378     // duplicate extension object
00379     if (findNodeExt) {
00380         call->addObject(static_cast<cObject*>(findNodeExt->dup()));
00381         call->addBitLength(findNodeExt->getBitLength());
00382     }
00383 
00384     return call;
00385 }
00386 
00387 //----------------------------------------------------------------------------
00388 //- Base configuration and state ---------------------------------------------
00389 //----------------------------------------------------------------------------
00390 //virtual public
00391 int IterativeLookup::compare(const OverlayKey& lhs, const OverlayKey& rhs) const
00392 {
00393     return overlay->distance(lhs, key).compareTo(overlay->distance(rhs, key));
00394 }
00395 
00396 
00397 //----------------------------------------------------------------------------
00398 //- Siblings and visited nodes management -----------------------------------
00399 //----------------------------------------------------------------------------
00400 bool IterativeLookup::addSibling(const NodeHandle& handle, bool assured)
00401 {
00402     bool result = false;
00403 
00404     EV << "[IterativeLookup::addSibling() @ " << overlay->getThisNode().getAddress()
00405                    << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00406                    << "    Adding potential sibling " << handle
00407                    << endl;
00408 
00409     majoritySiblings.insert(handle);
00410 
00411     if (config.verifySiblings && !assured && !getVisited(handle)) {
00412         // ping potential sibling for authentication
00413         if (siblings.isAddable(handle) && !getPinged(handle)) {
00414             int id = intuniform(1, 2147483647);
00415             int nonce = overlay->pingNode(handle, -1, 0, NULL, NULL, this, id);
00416             pendingPings.insert(make_pair(id, nonce));
00417             setPinged(handle);
00418         }
00419 
00420         return false;
00421     }
00422 
00423     if (numSiblings == 0) {
00424         if (handle.getKey() == key) {
00425             siblings.clear();
00426             siblings.push_back( handle );
00427             result = true;
00428         }
00429     } else {
00430         if (config.parallelPaths == 1 && !config.verifySiblings) {
00431             result = true;
00432             if (!siblings.isFull()) {
00433                 siblings.push_back(handle);
00434             }
00435         } else {
00436             if (siblings.add(handle) >= 0) {
00437                 result = true;
00438             }
00439         }
00440     }
00441 
00442     return result;
00443 }
00444 
00445 void IterativeLookup::setVisited(const TransportAddress& addr, bool visitedFlag)
00446 {
00447     if (visitedFlag)
00448         this->visited.insert(addr);
00449     else
00450         this->visited.erase(addr);
00451 }
00452 
00453 bool IterativeLookup::getVisited(const TransportAddress& addr)
00454 {
00455     return (visited.count(addr) != 0);
00456 }
00457 
00458 void IterativeLookup::setDead(const TransportAddress& addr)
00459 {
00460     dead.insert(addr);
00461 }
00462 
00463 bool IterativeLookup::getDead(const TransportAddress& addr)
00464 {
00465     return (dead.count(addr) != 0);
00466 }
00467 
00468 void IterativeLookup::setPinged(const TransportAddress& addr)
00469 {
00470     pinged.insert(addr);
00471 }
00472 
00473 bool IterativeLookup::getPinged(const TransportAddress& addr)
00474 {
00475     return (pinged.count(addr) != 0);
00476 }
00477 
00478 
00479 //----------------------------------------------------------------------------
00480 //- Parallel RPC distribution ------------------------------------------------
00481 //----------------------------------------------------------------------------
00482 void IterativeLookup::handleRpcResponse(BaseResponseMessage* msg,
00483                                    cPolymorphic* context,
00484                                    int rpcId, simtime_t rtt)
00485 {
00486     // check flags
00487     if (finished || !running)
00488         return;
00489 
00490     // get source, cast messages and mark node as visited
00491     const TransportAddress& src = msg->getSrcNode();
00492     FindNodeResponse* findNodeResponse = dynamic_cast<FindNodeResponse*>(msg);
00493     PingResponse* pingResponse = dynamic_cast<PingResponse*>(msg);
00494     FailedNodeResponse* failedNodeResponse =
00495     dynamic_cast<FailedNodeResponse*>(msg);
00496 
00497     if (pingResponse != NULL) {
00498         pendingPings.erase(rpcId);
00499         // add authenticated sibling
00500         addSibling(pingResponse->getSrcNode(), true);
00501     }
00502 
00503     // handle find node response
00504     if (findNodeResponse != NULL) {
00505 //      std::cout << "time: " << simTime() << " node: " << overlay->thisNode << " this: " << this << " received rpc with nonce: " << findNodeResponse->getNonce() << " from: " << findNodeResponse->getSrcNode() << endl;
00506 
00507         // check if rpc info is available, no -> exit
00508         if (rpcs.count(src) == 0)
00509             return;
00510 
00511         // get info
00512         RpcInfoVector infos = rpcs[src];
00513         rpcs.erase(src);
00514 
00515         // iterate
00516         bool rpcHandled = false;
00517 
00518         for (uint32_t i=0; i<infos.size(); i++) {
00519             // get info
00520             const RpcInfo& info = infos[i];
00521 
00522             // do not handle finished paths
00523             if (info.path->finished)
00524                 continue;
00525 
00526             // check if path accepts the message
00527             // make an exception for responses with siblings==true
00528             if (!rpcHandled &&
00529                     (info.path->accepts(info.vrpcId) ||
00530                     ((routingType == EXHAUSTIVE_ITERATIVE_ROUTING)
00531                             || (findNodeResponse->getSiblings() &&
00532                                 config.acceptLateSiblings)))) {
00533                 info.path->handleResponse(findNodeResponse);
00534                 rpcHandled = true;
00535             } else {
00536                 EV << "[IterativeLookup::handleRpcResponse()]\n"
00537                    << "    Path does not accept message with id " << info.vrpcId
00538                    << endl;
00539 
00540                 info.path->handleTimeout(NULL, findNodeResponse->getSrcNode(),
00541                                          info.vrpcId);
00542             }
00543 
00544             // count finished and successful paths
00545             if (info.path->finished) {
00546                 finishedPaths++;
00547 
00548                 // count total number of hops
00549                 accumulatedHops += info.path->hops;
00550 
00551                 if (info.path->success)
00552                     successfulPaths++;
00553             }
00554 
00555         }
00556     }
00557 
00558 
00559     // handle failed node response
00560     if (failedNodeResponse != NULL) {
00561         cPacket* findNodeExt = NULL;
00562         if (failedNodeResponse->hasObject("findNodeExt")) {
00563             findNodeExt =
00564                 (cPacket*)failedNodeResponse->removeObject("findNodeExt");
00565         }
00566 
00567         for (std::vector<IterativePathLookup*>::iterator i = paths.begin();
00568             i != paths.end(); i++) {
00569 
00570             (*i)->handleFailedNodeResponse(failedNodeResponse->getSrcNode(),
00571                                            findNodeExt,
00572                                            failedNodeResponse->getTryAgain());
00573         }
00574     }
00575 
00576     checkStop();
00577 }
00578 
00579 
00580 void IterativeLookup::handleRpcTimeout(BaseCallMessage* msg,
00581                                   const TransportAddress& dest,
00582                                   cPolymorphic* context, int rpcId,
00583                                   const OverlayKey& destKey)
00584 {
00585     // check flags
00586     if (finished || !running)
00587         return;
00588 
00589     if (dynamic_cast<PingCall*>(msg) != NULL) {
00590         pendingPings.erase(rpcId);
00591         checkStop();
00592         return;
00593     }
00594 
00595     // check if rpc info is available
00596     if (rpcs.count(dest)==0) {
00597         cout << "IterativeLookup::handleRpcTimeout(): RPC Timeout, but node"
00598                  << " is not in rpcs structure!" << endl;
00599         return;
00600     }
00601 
00602     // mark the node as dead
00603     setDead(dest);
00604 
00605     RpcInfoVector infos = rpcs[dest];
00606     rpcs.erase(dest);
00607 
00608     // iterate
00609     for (uint32_t i=0; i < infos.size(); i++) {
00610 
00611         const RpcInfo& info = infos[i];
00612 
00613         // do not handle finished paths
00614         if (info.path->finished)
00615             continue;
00616 
00617         // delegate timeout
00618         info.path->handleTimeout(msg, dest, info.vrpcId);
00619 
00620         // count finished and successful paths
00621         if (info.path->finished) {
00622             finishedPaths++;
00623 
00624             // count total number of hops
00625             accumulatedHops += info.path->hops;
00626 
00627             if (info.path->success)
00628                 successfulPaths++;
00629         }
00630     }
00631     checkStop();
00632 }
00633 
00634 void IterativeLookup::sendRpc(const NodeHandle& handle, FindNodeCall* call,
00635                               IterativePathLookup* listener, int rpcId)
00636 {
00637     // check flags
00638     if (finished || !running) {
00639         delete call;
00640         return;
00641     }
00642 
00643     // create rpc info
00644     RpcInfo info;
00645     info.path = listener;
00646     info.vrpcId = rpcId;
00647 
00648     // send new message
00649     if (rpcs.count(handle) == 0) {
00650         RpcInfoVector newVector;
00651 
00652         overlay->countFindNodeCall(call);
00653         newVector.nonce = overlay->sendUdpRpcCall(handle, call, NULL,
00654                                                   -1, 0, -1, this);
00655 
00656         //      std::cout << "time: " << simTime() << " node: " << overlay->thisNode << " new rpc with nonce: " << newVector.nonce << " to: " << handle << endl;
00657         rpcs[handle] = newVector;
00658     } else {
00659         EV << "[IterativeLookup::sendRpc()]\n"
00660            << "    RPC already sent...not sent again"
00661            << endl;
00662         delete call;
00663     }
00664 
00665     // register info
00666     rpcs[handle].push_back(info);
00667 }
00668 
00669 //----------------------------------------------------------------------------
00670 //- AbstractLookup implementation --------------------------------------------
00671 //----------------------------------------------------------------------------
00672 
00673 void IterativeLookup::lookup(const OverlayKey& key, int numSiblings,
00674                         int hopCountMax, int retries, LookupListener* listener)
00675 {
00676     EV << "[IterativeLookup::lookup() @ " << overlay->overlay->getThisNode().getAddress()
00677        << " (" << overlay->overlay->getThisNode().getKey().toString(16) << ")]\n"
00678        << "    Lookup of key " << key
00679        << endl;
00680 
00681     // check flags
00682     if (finished || running)
00683         return;
00684 
00685     // set params
00686     this->key = key;
00687     this->numSiblings = numSiblings;
00688     this->hopCountMax = hopCountMax;
00689     this->listener = listener;
00690     this->retries = retries;
00691 
00692     if ((routingType == EXHAUSTIVE_ITERATIVE_ROUTING)
00693         && (numSiblings > config.redundantNodes)) {
00694         throw cRuntimeError("IterativeLookup::lookup(): "
00695                   "With EXHAUSTIVE_ITERATIVE_ROUTING numRedundantNodes "
00696                   "must be >= numSiblings!");
00697     }
00698 
00699     // start lookup
00700     start();
00701 }
00702 
00703 const NodeVector& IterativeLookup::getResult() const
00704 {
00705     // return sibling vector
00706     return siblings;
00707 }
00708 
00709 bool IterativeLookup::isValid() const
00710 {
00711     return success && finished;
00712 }
00713 
00714 uint32_t IterativeLookup::getAccumulatedHops() const
00715 {
00716     return accumulatedHops;
00717 }
00718 
00719 IterativePathLookup::IterativePathLookup(IterativeLookup* lookup)
00720 {
00721     this->lookup = lookup;
00722     this->hops = 0;
00723     this->step = 0;
00724     this->pendingRpcs = 0;
00725     this->finished = false;
00726     this->success = false;
00727     this->overlay = lookup->overlay;
00728 
00729     if (lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
00730         // need to add some extra space for backup nodes, if we have to
00731         // remove failed nodes from the nextHops vector
00732         this->nextHops = LookupVector(2*(lookup->config.redundantNodes),
00733                                       lookup);
00734     } else {
00735         this->nextHops = LookupVector((lookup->config.redundantNodes),
00736                                       lookup);
00737     }
00738 }
00739 
00740 IterativePathLookup::~IterativePathLookup()
00741 {}
00742 
00743 bool IterativePathLookup::accepts(int rpcId)
00744 {
00745     if (finished) {
00746         return false;
00747     }
00748 
00749     // shall we use all responses, or only
00750     // the first one (rpcId == step)?
00751     if (lookup->config.useAllParallelResponses
00752         && lookup->config.merge) {
00753 
00754         return true;
00755     }
00756 
00757     return (rpcId == step);
00758 }
00759 
00760 void IterativePathLookup::handleResponse(FindNodeResponse* msg)
00761 {
00762     if (finished)
00763         return;
00764 
00765     if (simTime() > (lookup->startTime + LOOKUP_TIMEOUT)) {
00766         EV << "[IterativePathLookup::handleResponse()]\n"
00767            << "    Iterative lookup path timed out!"
00768            << endl;
00769         finished = true;
00770         success = false;
00771         return;
00772     }
00773 
00774     const NodeHandle& source = msg->getSrcNode();
00775     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00776     oldPos = oldNextHops.find(source);
00777     if (oldPos != oldNextHops.end()) oldNextHops.erase(oldPos);
00778 
00779     // don't count local hops
00780     if (lookup->overlay->getThisNode() != source) {
00781         hops++;
00782     }
00783 
00784     lookup->setVisited(source);
00785 
00786 //  if (source.getKey() == lookup->key) {
00787 //      cout << "received response from destination for key " << lookup->key
00788 //           << " with isSibling = " << msg->getSiblings() << endl;
00789 //  }
00790 
00791     step++;
00792 
00793     // decrease pending rpcs
00794     pendingRpcs--;
00795 
00796     if (msg->getClosestNodesArraySize() != 0) {
00797         // mode: merge or replace
00798         if (!lookup->config.merge) {
00799             nextHops.clear();
00800         }
00801     } else {
00802         //cout << "findNode() returned 0 nodes!" << endl;
00803     }
00804 
00805     int numNewRpcs = 0;
00806 
00807     // add new next hops
00808     for (uint32_t i=0; i < msg->getClosestNodesArraySize(); i++) {
00809         const NodeHandle& handle = msg->getClosestNodes(i);
00810 
00811         // add NodeHandle to next hops and siblings
00812         int pos = add(handle, source);
00813 
00814         // only send new rpcs if we've learned about new nodes
00815         if ((pos >= 0) && (pos < lookup->config.redundantNodes)) {
00816             numNewRpcs++;
00817         }
00818 
00819         // check if node was found
00820         if ((lookup->numSiblings == 0) && (handle.getKey() == lookup->key)) {
00821 
00822             lookup->addSibling(handle);
00823 
00824             // TODO: how do we resume, if the potential sibling doesn't authenticate?
00825             finished = true;
00826             success = true;
00827             return;
00828         } else {
00829             if (lookup->numSiblings != 0 &&
00830                 (lookup->routingType != EXHAUSTIVE_ITERATIVE_ROUTING) &&
00831                 msg->getSiblings()) {
00832 
00833                 //cout << "adding sibling " << handle << endl;
00834                 lookup->addSibling(handle);
00835             }
00836         }
00837     }
00838 
00839 #if 0
00840     cout << "nextHops.size " << nextHops.size()
00841          << " find node response " << msg->getClosestNodesArraySize()
00842          << " config " << lookup->config.redundantNodes << endl;
00843 
00844     cout << "looking for " << lookup->key << endl;
00845 
00846     for (uint32_t i=0; i < msg->getClosestNodesArraySize(); i++) {
00847         cout << "find node " << msg->getClosestNodes(i) << endl;
00848     }
00849 
00850     cout << "next Hops " << nextHops << endl;
00851 #endif
00852 
00853     // check if sibling lookup is finished
00854     if ((lookup->routingType != EXHAUSTIVE_ITERATIVE_ROUTING)
00855             && msg->getSiblings()
00856             && msg->getClosestNodesArraySize() != 0 &&
00857             lookup->numSiblings != 0) {
00858 
00859         finished = true;
00860         success = true;
00861         return;
00862     }
00863 
00864     // extract find node extension object
00865     cPacket* findNodeExt = NULL;
00866     if (msg->hasObject("findNodeExt")) {
00867         findNodeExt = (cPacket*)msg->removeObject("findNodeExt");
00868     }
00869 
00870     // If config.newRpcOnEveryResponse is true, send a new RPC
00871     // even if there was no lookup progress
00872     if ((numNewRpcs == 0) && lookup->config.newRpcOnEveryResponse) {
00873         numNewRpcs = 1;
00874     }
00875 
00876     // send next rpcs
00877     sendRpc(min(numNewRpcs, lookup->config.parallelRpcs), findNodeExt);
00878 
00879     delete findNodeExt;
00880 }
00881 
00882 void IterativePathLookup::sendNewRpcAfterTimeout(cPacket* findNodeExt)
00883 {
00884     // two alternatives to react on a timeout
00885     if (lookup->config.newRpcOnEveryTimeout) {
00886         // always send one new RPC for every timeout
00887         sendRpc(1, findNodeExt);
00888     } else if (pendingRpcs == 0) {
00889         // wait until all RPCs have timed out and then send alpha new RPCs
00890         sendRpc(lookup->config.parallelRpcs, findNodeExt);
00891     }
00892 }
00893 
00894 void IterativePathLookup::handleTimeout(BaseCallMessage* msg,
00895                                    const TransportAddress& dest, int rpcId)
00896 {
00897     if (finished)
00898         return;
00899 
00900     EV << "[IterativePathLookup::handleTimeout()]\n"
00901        << "    Timeout of RPC " << rpcId
00902        << endl;
00903 
00904     //std::cout << lookup->overlay->getThisNode() << ": Path timeout for node"
00905     //          << dest << endl;
00906 
00907     // For exhaustive-iterative remove dead nodes from nextHops vector
00908     // (which is also our results vector)
00909     if ((lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING)
00910             && lookup->getDead(dest)) {
00911         LookupVector::iterator it = nextHops.findIterator(
00912                             (dynamic_cast<const NodeHandle&>(dest)).getKey());
00913         if (it != nextHops.end()) {
00914             nextHops.erase(it);
00915         }
00916     }
00917 
00918     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00919     oldPos = oldNextHops.find(dest);
00920 
00921     // decrease pending rpcs
00922     pendingRpcs--;
00923 
00924     cPacket* findNodeExt = NULL;
00925     if (msg && msg->hasObject("findNodeExt")) {
00926         findNodeExt = static_cast<cPacket*>(
00927                 msg->removeObject("findNodeExt"));
00928     }
00929 
00930     if (simTime() > (lookup->startTime + LOOKUP_TIMEOUT)) {
00931         EV << "[IterativePathLookup::handleTimeout()]\n"
00932            << "    Iterative lookup path timed out!"
00933            << endl;
00934         delete findNodeExt;
00935         finished = true;
00936         success = false;
00937         return;
00938     }
00939 
00940     if (oldPos == oldNextHops.end() || (!lookup->config.failedNodeRpcs)) {
00941         sendNewRpcAfterTimeout(findNodeExt);
00942         delete findNodeExt;
00943     } else {
00944         if (oldPos->second.isUnspecified()) {
00945             // TODO: handleFailedNode should always be called for local
00946             // nodes, independent of config.failedNodeRpcs
00947             // Attention: currently this method is also called,
00948             // if a node responded and the path doesn't accept a message
00949             FindNodeCall* findNodeCall = dynamic_cast<FindNodeCall*>(msg);
00950             // answer was from local findNode()
00951 
00952             if (findNodeCall && lookup->overlay->handleFailedNode(dest)) {
00953                 NodeVector* retry = lookup->overlay->findNode(
00954                    findNodeCall->getLookupKey(), -1, lookup->numSiblings, msg);
00955 
00956                 for (NodeVector::iterator i = retry->begin(); i != retry->end(); i++) {
00957                     nextHops.add(LookupEntry(*i, NodeHandle::UNSPECIFIED_NODE, false));
00958                 }
00959 
00960                 delete retry;
00961             }
00962 
00963             sendNewRpcAfterTimeout(findNodeExt);
00964             delete findNodeExt;
00965 
00966         } else {
00967             FailedNodeCall* call = new FailedNodeCall("FailedNodeCall");
00968             call->setFailedNode(dest);
00969             call->setBitLength(FAILEDNODECALL_L(call));
00970             if (findNodeExt) {
00971                 call->addObject(findNodeExt);
00972                 call->addBitLength(findNodeExt->getBitLength());
00973             }
00974             lookup->overlay->countFailedNodeCall(call);
00975             lookup->overlay->sendUdpRpcCall(oldPos->second, call, NULL,
00976                                             -1, 0, -1, lookup);
00977         }
00978     }
00979 }
00980 
00981 void IterativePathLookup::handleFailedNodeResponse(const NodeHandle& src,
00982                                               cPacket* findNodeExt, bool retry)
00983 {
00984     if (finished) {
00985         return;
00986     }
00987 
00988     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00989     for (oldPos = oldNextHops.begin(); oldPos != oldNextHops.end(); oldPos++) {
00990         if ((! oldPos->second.isUnspecified()) &&
00991             (oldPos->second == src)) break;
00992     }
00993 
00994     if (oldPos == oldNextHops.end()) {
00995         return;
00996     }
00997 
00998     std::map<TransportAddress, NodeHandle>::iterator oldSrcPos =
00999         oldNextHops.find(src);
01000     const NodeHandle* oldSrc = &NodeHandle::UNSPECIFIED_NODE;
01001 
01002     if (oldSrcPos != oldNextHops.end()) {
01003         oldSrc = &(oldSrcPos->second);
01004     }
01005 
01006     if (retry) {
01007         // FIXME: This is needed for a node to be asked again when detecting
01008         // a failed node. It could pose problems when parallel lookups and
01009         // failed node recovery are both needed at the same time!
01010         lookup->setVisited(src, false);
01011 
01012         nextHops.add(LookupEntry(src, *oldSrc, false));
01013     }
01014 
01015     oldNextHops.erase(oldPos);
01016 
01017     sendNewRpcAfterTimeout(findNodeExt);
01018 }
01019 
01020 void IterativePathLookup::sendRpc(int num, cPacket* findNodeExt)
01021 {
01022     // path finished? yes -> quit
01023     if (finished)
01024         return;
01025 
01026     // check for maximum hop count
01027     if (lookup->hopCountMax && (hops >= lookup->hopCountMax)) {
01028         EV << "[IterativePathLookup::sendRpc()]\n"
01029            << "    Max hop count exceeded - lookup failed!"
01030            << endl;
01031         //cout << "[IterativePathLookup::sendRpc()]\n"
01032         //     << "    Max hop count exceeded - lookup failed!"
01033         //     << endl;
01034 
01035         finished = true;
01036         success = false;
01037 
01038         return;
01039     }
01040 
01041     // if strictParallelRpcs is true, limit concurrent in-flight requests
01042     // to config.parallelRpcs
01043     if (lookup->config.strictParallelRpcs) {
01044         num = min(num, lookup->config.parallelRpcs - pendingRpcs);
01045     }
01046 
01047     // try all remaining nodes
01048     if ((num == 0) && (pendingRpcs == 0)
01049             && !lookup->config.finishOnFirstUnchanged) {
01050         num = lookup->config.parallelRpcs;
01051         //cout << "trying all remaining nodes ("
01052         //     << lookup->numSiblings << ")" << endl;
01053     }
01054 
01055     // send rpc messages
01056     LookupVector::iterator it = nextHops.begin();
01057     int i = 0;
01058     for (LookupVector::iterator it = nextHops.begin();
01059          ((num > 0) && (i < lookup->config.redundantNodes)
01060           && (it != nextHops.end())); it++, i++)  {
01061 
01062         // ignore nodes to which we've already sent an RPC
01063         if (it->alreadyUsed || lookup->getDead(it->handle)) continue;
01064 
01065         // check if node has already been visited? no ->
01066         // TODO: doesn't work with Broose
01067         if ((!lookup->config.visitOnlyOnce) || (!lookup->getVisited(it->handle))) {
01068             // send rpc to node increase pending rpcs
01069             pendingRpcs++;
01070             num--;
01071             FindNodeCall* call = lookup->createFindNodeCall(findNodeExt);
01072             lookup->sendRpc(it->handle, call, this, step);
01073             oldNextHops[it->handle] = it->source;
01074 
01075             //cout << "Sending RPC to " << it->handle
01076             //     << " ( " << num << " more )"
01077             //     << " thisNode = " << lookup->overlay->getThisNode().getKey() << endl;
01078 
01079             // mark node as already used
01080             it->alreadyUsed = true;
01081         } else {
01082             //EV << "[IterativePathLookup::sendRpc()]\n"
01083             //   << "    Last next hop ("
01084             //   << it->handle
01085             //   << ") already visited."
01086             //   << endl;
01087 
01088 //            std::cout << "visited:" << std::endl;
01089 //            for (TransportAddress::Set::iterator it = lookup->visited.begin();
01090 //            it != lookup->visited.end(); it++)
01091 //                std::cout << *it << std::endl;
01092 //
01093 //            std::cout << "nextHops:" << std::endl;
01094 //            for (NodePairVector::iterator it = nextHops.begin();
01095 //                 it != nextHops.end(); it++)
01096 //                std::cout << it->first << std::endl;
01097         }
01098     }
01099 
01100     // no rpc sent, no pending rpcs?
01101     // -> failed for normal lookups
01102     // -> exhaustive lookups are always successful
01103     if (pendingRpcs == 0) {
01104         if (lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
01105             int i = 0;
01106             for (LookupVector::iterator it = nextHops.begin();
01107                  ((i < lookup->config.redundantNodes)
01108                          && (it != nextHops.end())); it++, i++)  {
01109                 lookup->addSibling(it->handle);
01110             }
01111 
01112             success = true;
01113         } else {
01114             success = false;
01115             //cout << "failed nextHops for key " << lookup->key << endl;
01116             //cout << nextHops << endl;
01117             EV << "[IterativePathLookup::sendRpc() @ " << overlay->getThisNode().getAddress()
01118                << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
01119                << "    Path failed (no further nodes to query) "
01120                << endl;
01121         }
01122 
01123         finished = true;
01124     }
01125     //cout << endl;
01126 }
01127 
01128 int IterativePathLookup::add(const NodeHandle& handle, const NodeHandle& source)
01129 {
01130     if (lookup->config.merge) {
01131         return nextHops.add(LookupEntry(handle, source, false));
01132     } else {
01133         nextHops.push_back(LookupEntry(handle, source, false));
01134         return (nextHops.size() - 1);
01135     }
01136 }
01137 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3