NeighborCache.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 
00025 #include <cassert>
00026 
00027 #include <TransportAddress.h>
00028 #include <NodeHandle.h>
00029 #include <PeerInfo.h>
00030 #include <GlobalStatisticsAccess.h>
00031 #include <CoordMessages_m.h>
00032 #include <GlobalNodeListAccess.h>
00033 #include <hashWatch.h>
00034 
00035 #include "NeighborCache.h"
00036 
00037 
00038 const std::vector<double> NeighborCache::coordsDummy;
00039 
00040 std::ostream& operator<<(std::ostream& os,
00041                          const NeighborCache::NeighborCacheEntry& entry)
00042 {
00043     if (entry.rttState == NeighborCache::RTTSTATE_VALID) {
00044         os << entry.rtt;
00045     } else {
00046         if (entry.rttState == NeighborCache::RTTSTATE_TIMEOUT) os << "TIMEOUT";
00047         else if (entry.rttState == NeighborCache::RTTSTATE_UNKNOWN) os << "UNKNOWN";
00048         else if (entry.rttState == NeighborCache::RTTSTATE_WAITING) os << "WAITING";
00049     }
00050     os << " (inserted: " << entry.insertTime;
00051 
00052     os << ", #contexts: "
00053        << entry.waitingContexts.size();
00054 
00055     if (!entry.nodeRef.isUnspecified()) os <<  ", <KEY>";
00056 
00057     //TODO entry.coordsInfo
00058 
00059     os << ")";
00060 
00061     return os;
00062 }
00063 
00064 
00065 Define_Module(NeighborCache);
00066 
00067 void NeighborCache::initializeApp(int stage)
00068 {
00069     if (stage == MAX_STAGE_COMPONENTS) {
00070         neighborCache.clear();
00071         WATCH_UNORDERED_MAP(neighborCache);
00072 
00073         enableNeighborCache = par("enableNeighborCache");
00074         rttExpirationTime = par("rttExpirationTime");
00075         maxSize = par("maxSize");
00076         doDiscovery = par("doDiscovery");
00077         ncsSendBackOwnCoords = par("ncsSendBackOwnCoords");
00078 
00079         // set default query types
00080         std::string temp = par("defaultQueryType").stdstringValue();
00081         if (temp == "exact")
00082             defaultQueryType = NEIGHBORCACHE_EXACT;
00083         else if (temp == "exact_timeout")
00084             defaultQueryType = NEIGHBORCACHE_EXACT_TIMEOUT;
00085         else if (temp == "available")
00086             defaultQueryType = NEIGHBORCACHE_AVAILABLE;
00087         else if (temp == "estimated")
00088             defaultQueryType = NEIGHBORCACHE_ESTIMATED;
00089         else throw cRuntimeError((std::string("Wrong query type: ")
00090             + temp).c_str());
00091 
00092         temp = par("defaultQueryTypeI").stdstringValue();
00093         if (temp == "available")
00094             defaultQueryTypeI = NEIGHBORCACHE_AVAILABLE;
00095         else if (temp == "estimated")
00096             defaultQueryTypeI = NEIGHBORCACHE_ESTIMATED;
00097         else throw cRuntimeError((std::string("Wrong query type (I): ")
00098             + temp).c_str());
00099 
00100         temp = par("defaultQueryTypeQ").stdstringValue();
00101         if (temp == "exact")
00102             defaultQueryTypeQ = NEIGHBORCACHE_EXACT;
00103         else if (temp == "exact_timeout")
00104             defaultQueryTypeQ = NEIGHBORCACHE_EXACT_TIMEOUT;
00105         else if (temp == "query")
00106             defaultQueryTypeQ = NEIGHBORCACHE_QUERY;
00107         else throw cRuntimeError((std::string("Wrong query type (Q): ")
00108         + temp).c_str());
00109 
00110         temp = par("ncsType").stdstringValue();
00111         if (temp == "none") ncs = NULL;
00112         else if (temp == "vivaldi") ncs = new Vivaldi();
00113         else if (temp == "svivaldi") ncs = new SVivaldi();
00114         else if (temp == "gnp") ncs = new Nps(); //TODO
00115         else if (temp == "nps") ncs = new Nps();
00116         else if (temp == "simple") ncs = new SimpleNcs();
00117         else throw cRuntimeError((std::string("Wrong NCS type: ")
00118             + temp).c_str());
00119 
00120         globalStatistics = GlobalStatisticsAccess().get();
00121 
00122         misses = 0;
00123         hits = 0;
00124 
00125         rttHistory = par("rttHistory");
00126         timeoutAccuracyLimit = par("timeoutAccuracyLimit");
00127 
00128         numMsg = 0;
00129         absoluteError = 0.0;
00130         relativeError = 0.0;
00131         numRttErrorToHigh = 0;
00132         numRttErrorToLow = 0;
00133         lastAbsoluteErrorPerNode.clear();
00134         WATCH(absoluteError);
00135         WATCH(relativeError);
00136         WATCH(numMsg);
00137     } else if (stage == MIN_STAGE_TIER_1) {
00138         if (ncs) ncs->init(this);
00139     }
00140 }
00141 
00142 
00143 void NeighborCache::finishApp()
00144 {
00145     if ((misses + hits) != 0) {
00146         globalStatistics
00147             ->addStdDev("NeighborCache: Ping hit rate",
00148                         ((double)hits / (double)(misses + hits)));
00149     }
00150 
00151     if (ncs && numMsg > 0) {
00152         globalStatistics->addStdDev("NeighborCache: NCS absolute RTT error",
00153                                     absoluteError / (double)numMsg);
00154         globalStatistics->addStdDev("NeighborCache: NCS relative RTT error",
00155                                     relativeError / (double)numMsg);
00156         globalStatistics->addStdDev("NeighborCache: number of messages/s",
00157                                     numMsg / SIMTIME_DBL(simTime() - creationTime));
00158         globalStatistics->addStdDev("NeighborCache: NCS percentage of RTT errors to high",
00159                                     (double)numRttErrorToHigh / (double)numMsg);
00160         globalStatistics->addStdDev("NeighborCache: NCS percentage of RTT errors to low",
00161                                     (double)numRttErrorToLow / (double)numMsg);
00162     }
00163 }
00164 
00165 
00166 NeighborCache::~NeighborCache()
00167 {
00168     delete ncs;
00169 }
00170 
00171 bool NeighborCache::insertNodeContext(const TransportAddress& handle,
00172                                      cPolymorphic* context,
00173                                      ProxListener* rpcListener,
00174                                      int rpcId)
00175 {
00176     if (!enableNeighborCache) return false;
00177     if (neighborCache.count(handle) == 0) {
00178         NeighborCacheEntry& entry = neighborCache[handle];
00179 
00180         entry.insertTime = simTime();
00181         entry.rttState = RTTSTATE_WAITING;
00182 
00183         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime,
00184                                                      handle));
00185 
00186         cleanupCache();
00187 
00188         assert(neighborCache.size() == neighborCacheExpireMap.size());
00189         return false;
00190     } else {
00191         NeighborCacheEntry& entry = neighborCache[handle];
00192 
00193         // waiting?
00194         if (entry.rttState == RTTSTATE_WAITING) {
00195             WaitingContext temp(rpcListener, context, rpcId);
00196             entry.waitingContexts.push_back(temp);
00197 
00198             return true;
00199         } else {
00200             if (entry.waitingContexts.size() > 0) {
00201                 throw cRuntimeError("not waiting for response,"
00202                                     " but additional contexts found!");
00203             }
00204 
00205             updateEntry(handle, entry.insertTime);
00206 
00207             entry.rttState = RTTSTATE_WAITING;
00208             entry.insertTime = simTime();
00209 
00210             return false;
00211         }
00212     }
00213 }
00214 
00215 
00216 NeighborCache::WaitingContexts NeighborCache::getNodeContexts(const TransportAddress& handle)
00217 {
00218     if (neighborCache.count(handle) == 0)
00219         throw cRuntimeError("NeighborCache error!");
00220     WaitingContexts temp = neighborCache[handle].waitingContexts;
00221     neighborCache[handle].waitingContexts.clear();
00222 
00223     return temp;
00224 }
00225 
00226 
00227 void NeighborCache::setNodeTimeout(const TransportAddress& handle)
00228 {
00229     //if (!enableNeighborCache) return;
00230 
00231     if (neighborCache.count(handle) == 0) {
00232         NeighborCacheEntry& entry = neighborCache[handle];
00233 
00234         entry.insertTime = simTime();
00235         entry.rttState = RTTSTATE_TIMEOUT;
00236 
00237         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime,
00238                                                      handle));
00239         cleanupCache();
00240     } else {
00241         NeighborCacheEntry& entry = neighborCache[handle];
00242 
00243         updateEntry(handle, entry.insertTime);
00244 
00245         entry.insertTime = simTime();
00246         entry.rttState = RTTSTATE_TIMEOUT;
00247 
00248         WaitingContexts waitingContexts = getNodeContexts(handle);
00249 
00250         for (uint32_t i = 0; i < waitingContexts.size(); ++i) {
00251             assert(waitingContexts[i].proxListener || !waitingContexts[i].proxContext);
00252             if (waitingContexts[i].proxListener) {
00253                 waitingContexts[i].proxListener->proxCallback(handle,
00254                                                               waitingContexts[i].id,
00255                                                               waitingContexts[i].proxContext,
00256                                                               Prox::PROX_TIMEOUT);
00257             }
00258         }
00259     }
00260     assert(neighborCache.size() == neighborCacheExpireMap.size());
00261 }
00262 
00263 
00264 void NeighborCache::updateNode(const NodeHandle& add, simtime_t rtt,
00265                                const NodeHandle& srcRoute,
00266                                AbstractNcsNodeInfo* ncsInfo)
00267 {
00268     Enter_Method_Silent();
00269 
00270     EV << "[NeighborCache::updateNode() @ " << thisNode.getIp()
00271            << " (" << thisNode.getKey().toString(16) << ")]\n"
00272            << "    inserting rtt(" << rtt << ") of node " << add.getIp()
00273            << endl;
00274 
00275     if (rtt <= 0) {
00276         delete ncsInfo;
00277         return; //TODO broose
00278     }
00279 
00280     bool deleteInfo = false;
00281 
00282     //if (enableNeighborCache) {
00283     if (neighborCache.count(add) == 0) {
00284         NeighborCacheEntry& entry = neighborCache[add];
00285 
00286         entry.insertTime = simTime();
00287         entry.rtt = rtt;
00288         entry.rttState = RTTSTATE_VALID;
00289         entry.nodeRef = add;
00290         entry.coordsInfo = ncsInfo;
00291         entry.lastRtts.push_back(rtt);
00292 
00293         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime, add));
00294 
00295         cleanupCache();
00296     } else {
00297         updateEntry(add, neighborCache[add].insertTime);
00298 
00299         NeighborCacheEntry& entry = neighborCache[add];
00300 
00301         entry.insertTime = simTime();
00302         if (entry.rttState != RTTSTATE_VALID || entry.rtt > rtt)
00303             entry.rtt = rtt;
00304         entry.rttState = RTTSTATE_VALID;
00305         entry.nodeRef = add;
00306 
00307         entry.lastRtts.push_back(rtt);
00308         if (entry.lastRtts.size()  > rttHistory) {
00309             entry.lastRtts.pop_front();
00310         }
00311 
00312         if (ncsInfo) {
00313             if (entry.coordsInfo) {
00314                 entry.coordsInfo->update(*ncsInfo);
00315                 deleteInfo = true;
00316             } else {
00317                 entry.coordsInfo = ncsInfo;
00318             }
00319         }
00320 
00321         WaitingContexts waitingContexts = getNodeContexts(add);
00322 
00323         for (uint32_t i = 0; i < waitingContexts.size(); ++i) {
00324             if (waitingContexts[i].proxListener) {
00325                 waitingContexts[i].proxListener
00326                 ->proxCallback(add,
00327                                waitingContexts[i].id,
00328                                waitingContexts[i].proxContext,
00329                                Prox(rtt, 1));
00330             }
00331         }
00332     }
00333     assert(neighborCache.size() == neighborCacheExpireMap.size());
00334 
00335     calcRttError(add, rtt);
00336 
00337     if (ncs) ncs->processCoordinates(rtt, *ncsInfo);
00338 
00339     // delete ncsInfo if old info is used
00340     if (deleteInfo) delete ncsInfo;
00341 }
00342 
00343 
00344 void NeighborCache::updateNcsInfo(const TransportAddress& node,
00345                                   AbstractNcsNodeInfo* ncsInfo)
00346 {
00347     Enter_Method_Silent();
00348 
00349     EV << "[NeighborCache::updateNcsInfo() @ " << thisNode.getIp()
00350        << " (" << thisNode.getKey().toString(16) << ")]\n"
00351        << "    inserting new NcsInfo of node " << node.getIp()
00352        << endl;
00353 
00354     if (neighborCache.count(node) == 0) {
00355         NeighborCacheEntry& entry = neighborCache[node];
00356 
00357         entry.insertTime = simTime();
00358         entry.coordsInfo = ncsInfo;
00359 
00360         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime, node));
00361 
00362         cleanupCache();
00363     } else {
00364         updateEntry(node, neighborCache[node].insertTime);
00365 
00366         NeighborCacheEntry& entry = neighborCache[node];
00367 
00368         if (ncsInfo) {
00369             if (entry.coordsInfo) {
00370                 entry.coordsInfo->update(*ncsInfo);
00371                 delete ncsInfo;
00372             } else {
00373                 entry.coordsInfo = ncsInfo;
00374             }
00375         }
00376     }
00377 }
00378 
00379 
00380 NeighborCache::Rtt NeighborCache::getNodeRtt(const TransportAddress &add)
00381 {
00382     // cache disabled or entry not there
00383     if (!enableNeighborCache ||
00384         add.isUnspecified() ||
00385         (neighborCache.count(add) == 0)) {
00386         misses++;
00387         return std::make_pair(0.0, RTTSTATE_UNKNOWN);
00388     }
00389 
00390     NeighborCacheEntry &entry = neighborCache[add];
00391 
00392     if (entry.rttState == RTTSTATE_WAITING ||
00393         entry.rttState == RTTSTATE_UNKNOWN)
00394         return std::make_pair(entry.rtt, entry.rttState);
00395     // entry expired
00396     if ((simTime() - entry.insertTime) >= rttExpirationTime) {
00397         entry.rttState = RTTSTATE_UNKNOWN;
00398         return std::make_pair(entry.rtt, RTTSTATE_UNKNOWN);
00399     }
00400     hits++;
00401     assert(!(entry.rtt == 0.0 && entry.rttState == RTTSTATE_VALID));
00402     return std::make_pair(entry.rtt, entry.rttState);
00403 }
00404 
00405 
00406 const NodeHandle& NeighborCache::getNodeHandle(const TransportAddress &add)
00407 {
00408     if (neighborCache.count(add) == 0) {
00409         throw cRuntimeError("NeighborCache.cc: getNodeHandle was asked for "
00410                             "a non-existent node reference.");
00411     }
00412     return neighborCache[add].nodeRef;
00413 }
00414 
00415 
00416 bool NeighborCache::cleanupCache()
00417 {
00418     bool result = false;
00419     uint32_t size = neighborCache.size();
00420 
00421     if (size > maxSize) {
00422         neighborCacheExpireMapIterator it;
00423         for (uint32_t i = 0; i < (size - (maxSize / 2)); ++i) {
00424             it = neighborCacheExpireMap.begin();
00425             if ((neighborCache[it->second].rttState == RTTSTATE_WAITING) ||
00426                 (neighborCache[it->second].insertTime == simTime())) {
00427                 break;
00428             }
00429             neighborCache.erase(it->second);
00430             neighborCacheExpireMap.erase(it);
00431             result = true;
00432         }
00433     }
00434     assert(neighborCache.size() == neighborCacheExpireMap.size());
00435     return result;
00436 }
00437 
00438 
00439 void NeighborCache::updateEntry(const TransportAddress& address,
00440                                 simtime_t insertTime)
00441 {
00442     neighborCacheExpireMapIterator it =
00443         neighborCacheExpireMap.lower_bound(insertTime);
00444     while (it->second != address) ++it;
00445     neighborCacheExpireMap.erase(it);
00446     neighborCacheExpireMap.insert(std::make_pair(simTime(),
00447                                                  address));
00448     assert(neighborCache.size() == neighborCacheExpireMap.size());
00449 }
00450 
00451 //TODO
00452 TransportAddress NeighborCache::getNearestNode(uint8_t maxLayer)
00453 {
00454     TransportAddress nearestNode = TransportAddress::UNSPECIFIED_NODE;
00455     simtime_t nearestNodeRtt = MAXTIME;
00456     NeighborCacheIterator it;
00457 
00458     for(it = neighborCache.begin(); it != neighborCache.end(); it++ ) {
00459         if (it->second.rtt < nearestNodeRtt &&
00460             it->second.rtt > 0 /*&&
00461             it->second.coordsInfo.npsLayer < maxLayer+1 &&
00462             it->second.coordsInfo.npsLayer > 0*/) {
00463             nearestNode.setIp(it->first.getIp());
00464             nearestNodeRtt = it->second.rtt;
00465             nearestNode.setPort(it->second.nodeRef.getPort());
00466         }
00467     }
00468 
00469     return nearestNode;
00470 }
00471 
00472 
00473 bool NeighborCache::isEntry(const TransportAddress &node)
00474 {
00475     if (neighborCache.count(node) > 0) return true;
00476     return false;
00477 }
00478 
00479 
00480 // Vivaldi stuff
00481 double NeighborCache::getAvgAbsPredictionError()
00482 {
00483     /*
00484     //TODO retain and consider the last measured RTTs not the last error(s)
00485     double absoluteDiff = 0.0;
00486     uint32_t numNeighbors = 0;
00487 
00488     for (std::map<TransportAddress, std::vector<double> >::iterator it =
00489         lastAbsoluteErrorPerNode.begin(); it != lastAbsoluteErrorPerNode.end();
00490         it++) {
00491         double tempAbsoluteDiff = 0.0;
00492         for (uint32_t i = 0; i < it->second.size(); i++) {
00493             tempAbsoluteDiff += it->second.at(i);
00494         }
00495         absoluteDiff += (tempAbsoluteDiff / it->second.size());
00496         numNeighbors++;
00497     }
00498 
00499     absoluteDiff /= numNeighbors;
00500     return (absoluteDiff > 1.0) ? 1.0 : absoluteDiff;
00501      */
00502 
00503     // old version
00504     //if (neighborCache.size() < 2 || sampleSize == 0) return 1.0;
00505 
00506     double absoluteDiff = 0;
00507     uint32_t numNeighbors = 0;
00508     uint32_t sampleSize = 32; //test
00509 
00510     for (std::map<simtime_t, TransportAddress>::reverse_iterator it =
00511          neighborCacheExpireMap.rbegin();
00512          it != neighborCacheExpireMap.rend() &&
00513          numNeighbors < sampleSize; ++it) {
00514         NeighborCacheEntry& cacheEntry = neighborCache[it->second];
00515 
00516         double dist = ncs->getOwnNcsInfo().getDistance(*cacheEntry.coordsInfo);
00517 
00518         if (dist != 0 && cacheEntry.rttState == RTTSTATE_VALID) {
00519             double predictionError = fabs(dist - SIMTIME_DBL(cacheEntry.rtt));
00520 
00521             //test: error weighted
00522             //if (it->second.coordErr < 1) {
00523             //    predictionError /= it->second.coordErr;
00524             //}
00525             //test: age weighted
00526             //if ((simTime() - it->second.insertTime) > 1) {
00527             //    predictionError /= (simTime() - it->second.insertTime);
00528             //}
00529 
00530             numNeighbors++;
00531             absoluteDiff += predictionError;
00532         }
00533     }
00534     assert(numNeighbors != 0);
00535     absoluteDiff /= numNeighbors;
00536 
00537     return (absoluteDiff > 1.0) ? 1.0 : absoluteDiff;
00538 }
00539 
00540 
00541 void NeighborCache::handleReadyMessage(CompReadyMessage* readyMsg)
00542 {
00543     if (readyMsg->getReady() && readyMsg->getComp() == BOOTSTRAPLIST_COMP) {
00544         if (doDiscovery) {
00545             //TODO
00546             // 1. ask bootstrap node for other nodes and his coordinates
00547             // 2. probe other nodes and optionally ask them for more nodes
00548             //    (try to get close as well as distant nodes)
00549             // sendReadyMessage();
00550         } else {
00551             sendReadyMessage();
00552         }
00553     }
00554     delete readyMsg;
00555 }
00556 
00557 
00558 void NeighborCache::handleTimerEvent(cMessage* msg)
00559 {
00560     if (ncs) {
00561         ncs->handleTimerEvent(msg);
00562     }
00563 }
00564 
00565 
00566 bool NeighborCache::handleRpcCall(BaseCallMessage* msg)
00567 {
00568     if (ncs) {
00569         return ncs->handleRpcCall(msg);
00570     }
00571 
00572     return false;
00573 }
00574 
00575 
00576 // Prox stuff
00577 Prox NeighborCache::getProx(const TransportAddress &node,
00578                               NeighborCacheQueryType type,
00579                               int rpcId,
00580                               ProxListener *listener,
00581                               cPolymorphic *contextPointer)
00582 {
00583     Enter_Method("getProx()");
00584 
00585     if (!enableNeighborCache) {
00586         queryProx(node, rpcId, listener, contextPointer);
00587         return Prox::PROX_UNKNOWN;
00588     }
00589 
00590     if (node == overlay->getThisNode()) {
00591         delete contextPointer;
00592         return Prox::PROX_SELF;
00593     }
00594 
00595     bool sendQuery = false;
00596     Prox result = Prox::PROX_UNKNOWN;
00597     Rtt rtt = getNodeRtt(node);
00598 
00599     //countGetProxTotal++;
00600     if (type == NEIGHBORCACHE_DEFAULT) type = defaultQueryType;
00601     else if (type == NEIGHBORCACHE_DEFAULT_IMMEDIATELY) type = defaultQueryTypeI;
00602     else if (type == NEIGHBORCACHE_DEFAULT_QUERY) type = defaultQueryTypeQ;
00603 
00604     switch(type) {
00605         case NEIGHBORCACHE_EXACT:
00606             if (rtt.second == RTTSTATE_TIMEOUT) {
00607                 // if timeout, return unknown, and send a query!
00608                 sendQuery = true;
00609             } else if (rtt.second == RTTSTATE_WAITING) {
00610                 // if a query was sent, return UNKNOWN
00611                 sendQuery = true; //just inserting a context, no real ping is sent
00612             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00613                 // if no entry known, send a query and return UNKNOWN
00614                 sendQuery = true;
00615             } else {
00616                 // else, return whatever we have
00617                 result = rtt.first;
00618             }
00619             break;
00620         case NEIGHBORCACHE_EXACT_TIMEOUT:
00621             if (rtt.second == RTTSTATE_TIMEOUT) {
00622                 // if timeout, return that
00623                 result = Prox::PROX_TIMEOUT;
00624             } else if (rtt.second == RTTSTATE_WAITING) {
00625                 // if a query was sent, return UNKNOWN
00626                 sendQuery = true; //just inserting a context, no real ping is sent
00627             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00628                 // if no entry known, send a query and return UNKNOWN
00629                 sendQuery = true;
00630             } else {
00631                 // else, return whatever we have
00632                 result = rtt.first;
00633             }
00634             break;
00635         case NEIGHBORCACHE_ESTIMATED:
00636             if (rtt.second == RTTSTATE_TIMEOUT) {
00637                 // if timeout, return that
00638                 result = Prox::PROX_TIMEOUT;
00639             } else if (rtt.second == RTTSTATE_WAITING) {
00640                 // if a query was sent, return an estimate
00641                 result = estimateProx(node);
00642             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00643                 // if no entry known, return an estimate
00644                 result = estimateProx(node);
00645             } else {
00646                 // else return whatever we have
00647                 result = rtt.first;
00648             }
00649             break;
00650         case NEIGHBORCACHE_AVAILABLE:
00651             if (rtt.second == RTTSTATE_TIMEOUT) {
00652                 // if timeout, return that.
00653                 result = Prox::PROX_TIMEOUT;
00654             } else if ((rtt.second == RTTSTATE_WAITING) ||
00655                        (rtt.second == RTTSTATE_UNKNOWN)) {
00656                 // if a query was sent or entry unknown, return UNKNOWN
00657             } else {
00658                 // else return what we have
00659                 result = rtt.first;
00660             }
00661             break;
00662         case NEIGHBORCACHE_QUERY:
00663             // simply send a query and return UNKNOWN
00664             sendQuery = true;
00665             break;
00666         default:
00667             throw cRuntimeError("Unknown query type!");
00668             break;
00669 
00670     }
00671     if (sendQuery) {
00672         if (!insertNodeContext(node, contextPointer, listener, rpcId)) {
00673             queryProx(node, rpcId, listener, contextPointer);
00674         }
00675     } else delete contextPointer;
00676 
00677     return result;
00678 }
00679 
00680 Prox NeighborCache::estimateProx(const TransportAddress &node)
00681 {
00682     Enter_Method("estimateProx()");
00683 
00684     Rtt rtt = getNodeRtt(node);
00685 
00686     if (rtt.second != RTTSTATE_UNKNOWN) return rtt.first;
00687 
00688     if (ncs && neighborCache.count(node)) {
00689         return getCoordinateBasedProx(node);
00690     }
00691 
00692     return Prox::PROX_UNKNOWN;
00693 }
00694 
00695 void NeighborCache::queryProx(const TransportAddress &node,
00696                               int rpcId,
00697                               ProxListener *listener,
00698                               cPolymorphic *contextPointer)
00699 {
00700     Enter_Method("queryProx()");
00701 
00702     WaitingContext temp(listener, contextPointer, rpcId);
00703 
00704     if (neighborCache.count(node) == 0) {
00705         NeighborCacheEntry& entry = neighborCache[node];
00706 
00707         entry.waitingContexts.push_back(temp);
00708         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime, node));
00709         cleanupCache();
00710     } else {
00711         NeighborCacheEntry& entry = neighborCache[node];
00712         entry.waitingContexts.push_back(temp);
00713     }
00714     assert(neighborCache.size() == neighborCacheExpireMap.size());
00715 
00716     // TODO: this ping traffic is accounted application data traffic!
00717     pingNode(node, -1, 0, NULL, "PING");
00718 }
00719 
00720 Prox NeighborCache::getCoordinateBasedProx(const TransportAddress& node)
00721 {
00722     if (ncs && isEntry(node)) {
00723         const AbstractNcsNodeInfo* temp = getNodeCoordsInfo(node);
00724         if (temp) return ncs->getCoordinateBasedProx(*temp);
00725     }
00726     return Prox::PROX_UNKNOWN;
00727 }
00728 
00729 
00730 const AbstractNcsNodeInfo* NeighborCache::getNodeCoordsInfo(const TransportAddress &node)
00731 {
00732     if (neighborCache.count(node) == 0) {
00733         throw cRuntimeError("NeighborCache.cc: getNodeCoords was asked for "
00734                             "a non-existent node reference.");
00735     }
00736     return neighborCache[node].coordsInfo;
00737 }
00738 
00739 
00740 void NeighborCache::calcRttError(const NodeHandle& handle, simtime_t rtt)
00741 {
00742     if (!ncs) return;
00743 
00744     // Check if data collection can start
00745     if (!globalStatistics->isMeasuring()) return;
00746 
00747     Prox prox = getCoordinateBasedProx(handle);
00748     if (prox == Prox::PROX_UNKNOWN) return;
00749 
00750     //calculate absolute rtt error of the last message
00751     double tempRttError = prox.proximity - SIMTIME_DBL(rtt);
00752 
00753     if (tempRttError < 0){
00754         tempRttError *= -1;
00755         ++numRttErrorToLow;
00756     } else ++numRttErrorToHigh;
00757 
00758     numMsg++;
00759     absoluteError += tempRttError;
00760     relativeError += tempRttError / SIMTIME_DBL(rtt);
00761 
00762     globalStatistics->recordOutVector("NCS: absolute Rtt Error",
00763                                       tempRttError);
00764     globalStatistics->recordOutVector("NCS: relative Rtt Error",
00765                                       (tempRttError / SIMTIME_DBL(rtt)));
00766 }
00767 
00768 
00769 std::pair<simtime_t, simtime_t> NeighborCache::getMeanVarRtt(const TransportAddress &node,
00770                                                              bool returnVar)
00771 {
00772     if (neighborCache.count(node) == 0) {
00773         throw cRuntimeError("NeighborCache.cc: getMeanVarRtt was asked for"
00774                             "a non-existent node reference.");
00775     }
00776 
00777     uint16_t size = neighborCache[node].lastRtts.size();
00778     if (size == 0) return std::make_pair(-1.0,-1.0);
00779 
00780     simtime_t rttSum = 0;
00781     for (int i = 0; i < size; i++){
00782         rttSum += neighborCache[node].lastRtts[i];
00783     }
00784     simtime_t meanRtt = rttSum / size;
00785     if (!returnVar) {
00786         return std::make_pair(meanRtt, -1.0);
00787     }
00788     if (size == 1) {
00789         return std::make_pair(meanRtt, 0.0);
00790     }
00791 
00792     double sum = 0.0;
00793     for (int i = 0; i < size; i++){
00794         simtime_t tempRtt = neighborCache[node].lastRtts.at(i) - meanRtt;
00795         sum += (SIMTIME_DBL(tempRtt) * SIMTIME_DBL(tempRtt));
00796     }
00797 
00798     return std::make_pair(meanRtt, (sum / size));
00799 }
00800 
00801 
00802 simtime_t NeighborCache::getNodeTimeout(const NodeHandle &node)
00803 {
00804     simtime_t timeout = getRttBasedTimeout(node);
00805     if (timeout == -1 && ncs) return getNcsBasedTimeout(node);
00806     return timeout;
00807 }
00808 
00809 
00810 //Calculate timeout with RTT
00811 simtime_t NeighborCache::getRttBasedTimeout(const NodeHandle &node)
00812 {
00813     simtime_t timeout = -1;
00814 
00815     // check if an entry is available in NeighborCache
00816     if (isEntry(node)) {
00817         std::pair<simtime_t, simtime_t> temp = getMeanVarRtt(node, true);
00818         simtime_t meanRtt = temp.first;
00819         simtime_t varRtt = temp.second;
00820 
00821         // TODO return value even if node has timed out
00822         if (meanRtt == -1) return -1;
00823         if (varRtt > 0) {
00824             // like TCP
00825             timeout = meanRtt + 4 * varRtt;
00826         } else {
00827             // only one RTT is available
00828             timeout = meanRtt * 1.2;
00829         }
00830         // adjustment
00831         timeout *= RTT_TIMEOUT_ADJUSTMENT;
00832         //if (timeout > SIMTIME_DBL(defaultTimeout)) return -1;
00833     }
00834     return timeout;
00835 }
00836 
00837 //Calculate timeout with NCS
00838 simtime_t NeighborCache::getNcsBasedTimeout(const NodeHandle &node)
00839 {
00840     double timeout = -1;
00841     Prox prox = Prox::PROX_UNKNOWN;
00842 
00843     // check if an entry is available in NeighborCache
00844     if (isEntry(node)) {
00845         prox = getProx(node, NEIGHBORCACHE_ESTIMATED);
00846 
00847         if (prox != Prox::PROX_UNKNOWN  && prox != Prox::PROX_TIMEOUT &&
00848             prox.proximity > 0 && prox.accuracy > timeoutAccuracyLimit) {
00849             timeout = prox.proximity + (6 * (1 - prox.accuracy));
00850             timeout += NCS_TIMEOUT_CONSTANT;
00851         } else return -1;
00852 
00853         if (/*timeout > SIMTIME_DBL(defaultTimeout) ||*/ timeout < 0)
00854             return -1;
00855     }
00856     return timeout;
00857 }
00858