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

Generated on Tue Sep 8 17:26:53 2009 for OverSim by  doxygen 1.5.8