OverSim
Nps.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2009 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
24 #include <GlobalNodeList.h>
25 #include <PeerInfo.h>
26 #include <RpcMacros.h>
27 #include <NeighborCache.h>
28 #include <GlobalNodeListAccess.h>
29 #include <Landmark.h>
30 #include <UnderlayConfigurator.h>
31 #include <SimpleNodeEntry.h>
32 #include <SimpleInfo.h>
34 #include <GlobalStatistics.h>
35 
36 #include <Nps_m.h>
37 
38 #include <Nps.h>
39 
40 
41 void Nps::init(NeighborCache* neighborCache)
42 {
43  this->neighborCache = neighborCache;
44  overlay = neighborCache->overlay;
45 
46  maxLayer = neighborCache->par("npsMaxLayer");
47  dimensions = neighborCache->par("gnpDimensions");
48  landmarkTimeout = neighborCache->par("gnpLandmarkTimeout");
49 
52 
53  ready = false;
54 
55  receivedCalls = 0;
56  pendingRequests = 0;
57  coordCalcRuns = neighborCache->par("gnpCoordCalcRuns");
58 
59  WATCH(*ownCoords);
60  WATCH_VECTOR(landmarkSet);
61 
64 
65  if (neighborCache->getParentModule()->getModuleByRelativePath("tier1")
66  ->getModuleByRelativePath("landmark") == NULL) {
67  landmarkTimer = new cMessage("landmarkTimer");
68  neighborCache->scheduleAt(simTime() + landmarkTimeout, landmarkTimer);
69  } else {
70  // GNP-landmark or NPS-Layer-0-landmark
71  ownCoords->setLayer(0); //TODO double, see Landmark.cc
72  }
73 }
74 
75 void Nps::handleTimerEvent(cMessage* msg)
76 {
77  // process landmark timer message
78  if (msg == landmarkTimer) {
79  if (enoughLandmarks()) {
80  delete msg;
81  //std::cout << "[" << getThisNode().getIp() << "] (Re-)Trying to contact landmarks" << std::endl;
83  } else {
84  neighborCache->scheduleAt(simTime() + landmarkTimeout, msg);
85  }
86  }
87 }
88 
90  cPolymorphic* context,
91  int rpcId, simtime_t rtt)
92 {
93  // call rpc stubs
94  RPC_SWITCH_START( msg );
95  RPC_ON_RESPONSE( CoordsReq ) {
96  coordsReqRpcResponse(_CoordsReqResponse, context, rpcId, rtt);
97  }
98 #ifdef EXTJOIN_DISCOVERY
99  RPC_ON_RESPONSE( RttToNode ) {
100  rttToNodeRpcResponse(_RttToNodeResponse, context, rpcId, rtt);
101  }
102 #endif
103  RPC_SWITCH_END( );
104 
105  return;
106 }
107 
109  const TransportAddress& dest,
110  cPolymorphic* context, int rpcId,
111  const OverlayKey& destKey)
112 {
113  RPC_SWITCH_START( msg ) {
114 
115  RPC_ON_CALL( CoordsReq ) {
116  if (true/*doingNodeMeasurement()*/) {//TODO
117 #ifdef EXTJOIN_DISCOVERY
118  if (getPendingRttsReq(dest) == -1) {
119  RttToNodeCall* call = getNodeMessage(dest);
120 
121  RttToNodeResponse* rttRes = new RttToNodeResponse("RttToNodeXRes");
122  rttRes->setPingedNode(dest);
123  rttRes->setRttToNode(0);
124  Coords tempOwnCoords;
125  tempOwnCoords = getOwnCoordinates();
126  rttRes->setOwnCoordinatesArraySize(tempOwnCoords.size());
127  for (uint i = 0; i < tempOwnCoords.size(); i++) {
128  rttRes->setOwnCoordinates(i, tempOwnCoords[i]);
129  }
130  sendRpcResponse(call, rttRes);
131  deleteNodeMeasurement(dest);
132  } else {
133 #endif
134  updateNodeMeasurement(dest, -1);
135 #ifdef EXTJOIN_DISCOVERY
136  }
137 #endif
138 
139  } else {
140  pendingRequests--;
141  }
142  }
143 #ifdef EXTJOIN_DISCOVERY
144  RPC_ON_CALL( RttToNode ) {
145  updateNodeMeasurement(dest, -1);
146  }
147 #endif
148  }
149  RPC_SWITCH_END( )
150 }
151 
153 {
154  RPC_SWITCH_START( msg );
155  RPC_DELEGATE( CoordsReq, coordsReqRpc );
156  //if (discovery)
157  RPC_SWITCH_END( );
158 
159  return RPC_HANDLED;
160 }
161 
163 {
164  receivedCalls++;
165  CoordsReqResponse* coordResp = new CoordsReqResponse("CoordsReqResp");
166  coordResp->setLayer(getOwnLayer()); //TODO
167  coordResp->setNcsInfoArraySize(dimensions + 1);
168 
169  //if (getOwnLayer() != 0) {
170  // ordinary node
171 
172  const Coords& ownCoordinates = getOwnCoordinates();
173 
174  uint8_t i;
175  for (i = 0; i < ownCoordinates.size(); ++i) {
176  coordResp->setNcsInfo(i, ownCoordinates[i]);
177  }
178  coordResp->setNcsInfo(i, getOwnLayer());
179 
180  /*} else {
181  // landmark node
182  Landmark* landmark = check_and_cast<Landmark*>(neighborCache->getParentModule()
183  ->getModuleByRelativePath("tier1.landmark"));
184  assert(landmark);
185  const Coords& ownCoordinates = landmark->getOwnNpsCoords();
186 
187  uint8_t i;
188  for (i = 0; i < ownCoordinates.size(); ++i) {
189  coordResp->setNcsInfo(i, ownCoordinates[i]);
190  }
191  coordResp->setNcsInfo(i, getOwnLayer());
192  }*/
193 
194  coordResp->setBitLength(COORDSREQRESPONSE_L(coordResp));
195  neighborCache->sendRpcResponse(msg, coordResp);
196 }
197 
198 #ifdef EXTJOIN_DISCOVERY
199 void Nps::rttToNodeRpc(RttToNodeCall* msg)
200 {
201  incReceivedCalls();
202  TransportAddress dest = msg->getNodeToPing();
203 //std::cout << "Set Node Message";
204  setNodeMessage(dest, msg);
205  sendCoordsReqCall(dest, -1);
206 }
207 #endif
208 
210  cPolymorphic* context, int rpcId, simtime_t rtt)
211 {
212  pendingRequests--;
213  NodeHandle& srcNode = response->getSrcNode();
214 
215  Coords tempCoords;
216  for (uint8_t i = 0; i < response->getNcsInfoArraySize(); i++) {
217  tempCoords.push_back(response->getNcsInfo(i));
218  }
219  GnpNpsCoordsInfo* coordsInfo =
220  static_cast<GnpNpsCoordsInfo*>(createNcsInfo(tempCoords));
221 
222  EV << "[Nps::coordsReqRpcResponse() @ " << neighborCache->thisNode.getIp()
223  << " (" << neighborCache->thisNode.getKey().toString(16) << ")]\n received landmark coords: "
224  << tempCoords[0];
225 
226  for (uint8_t i = 1; i < dimensions; i++) {
227  EV << ", " << tempCoords[i];
228  }
229  EV << " (rtt = " << rtt << ")" << endl;
230 
231 #ifdef EXTJOIN_DISCOVERY
232  if (doingDiscovery()) {
233  //if in Discovery insert RTT only if lower then already set RTT
234  if ((isEntry(srcNode) && rtt < getNodeRtt(srcNode))
235  || (isEntry(srcNode) && getNodeRtt(srcNode) < 0) ) {
236  updateNode(srcNode, rtt, tempCoords, 0);
237  } else if (!(isEntry(srcNode))) {
238  updateNode(srcNode, rtt, tempCoords, 0);
239  } else {
240  updateNode(srcNode, getNodeRtt(srcNode), tempCoords, 0);
241  }
242  setNodeLayer(srcNode, tempLayer);
243  }
244  else if (doingNodeMeasurement()) {
245  if (getPendingRttsReq(srcNode) == -1) {
246  updateNode(srcNode, rtt, tempCoords, 0);
247  setNodeLayer(srcNode, tempLayer);
248  RttToNodeCall* prevCall = getNodeMessage(srcNode);
249 
250  RttToNodeResponse* rttRes = new RttToNodeResponse("RttToNodeXRes");
251  rttRes->setPingedNode(srcNode);
252  rttRes->setRttToNode(rtt);
253  Coords tempOwnCoords;
254  tempOwnCoords = getOwnCoordinates();
255  rttRes->setOwnCoordinatesArraySize(tempOwnCoords.size());
256  for (uint i = 0; i < tempOwnCoords.size(); i++) {
257  rttRes->setOwnCoordinates(i, tempOwnCoords[i]);
258  }
259 
260  sendRpcResponse(prevCall, rttRes);
261  deleteNodeMeasurement(srcNode);
262  } else {
263  updateNode(srcNode, rtt, tempCoords, 0);
264  setNodeLayer(srcNode, tempLayer);
265  if (checkCoordinates(getOwnCoordinates(), tempCoords, rtt)) {
266  updateNodeMeasurement(srcNode, -1, 0, 1);
267  } else {
268  updateNodeMeasurement(srcNode, -1, 0, 0);
269  }
270  }
271  }
272  else
273 #endif
274  if (pendingRequests == 0) {
275  // got all responses, now compute own coordinates and join overlay
277  coordsInfo);
278 
279  std::vector<LandmarkDataEntry> probedLandmarks;
280  if (getLandmarkSetSize() < dimensions + 1) {
281  setLandmarkSet(dimensions + 1, maxLayer, &landmarkSet);
282  }
283 
284  for (std::vector<TransportAddress>::iterator it = landmarkSet.begin();
285  it != landmarkSet.end(); ++it) {
286  const GnpNpsCoordsInfo* tempInfo =
287  dynamic_cast<const GnpNpsCoordsInfo*>(neighborCache->getNodeCoordsInfo(*it));
288 
289  assert(tempInfo);
290 
291  LandmarkDataEntry temp;
292  temp.coordinates.resize(tempInfo->getDimension());
293  temp.rtt = neighborCache->getNodeRtt(*it).first;
294  temp.layer = tempInfo->getLayer();
295  for (uint8_t i = 0; i < tempInfo->getDimension(); ++i) {
296  temp.coordinates[i] = tempInfo->getCoords(i);
297  }
298  temp.ip = NULL;
299 
300  probedLandmarks.push_back(temp);
301  }
302  assert(probedLandmarks.size() > 0);
303 
304  setOwnCoordinates(computeOwnCoordinates(probedLandmarks));
305  setOwnLayer(computeOwnLayer(probedLandmarks));
306 
307  Coords coords = getOwnCoordinates();
308  EV << "[Nps::coordsReqRpcResponse() @ " << neighborCache->thisNode.getIp()
309  << " (" << neighborCache->thisNode.getKey().toString(16) << ")]\n setting own coords: "
310  << coords[0];
311  for (uint8_t i = 1; i < dimensions; i++) {
312  EV << ", " << coords[i];
313  }
314  EV << endl;
315 
316  ready = true;
317 
318  //test
319  /*
320  ChurnGenerator* lmChurnGen = NULL;
321  for (uint8_t i = 0; i < neighborCache->underlayConfigurator->getChurnGeneratorNum(); i++) {
322  ChurnGenerator* searchedGen;
323  searchedGen = neighborCache->underlayConfigurator->getChurnGenerator(i);
324  if (searchedGen->getNodeType().overlayType != "oversim.common.cbr.LandmarkModules") {
325  lmChurnGen = searchedGen;
326  }
327  }
328  */
329 
330  SimpleNodeEntry* entry =
331  dynamic_cast<SimpleInfo*>(globalNodeList->
332  getPeerInfo(neighborCache->thisNode.getIp()))->getEntry();
333 
334  double error = 0;
335  for (uint8_t i = 1; i < entry->getDim(); i++) {
336  error += pow(coords[i] - entry->getCoords(i), 2);
337  }
338  error = sqrt(error);
339  //std::cout << "error = " << error << std::endl;
340 
342  ->addStdDev("NPS: Coordinate difference", error);
343 
344  neighborCache->neighborCache.clear(); //TODO
345  neighborCache->neighborCacheExpireMap.clear(); //TODO
346 
347  neighborCache->getParentModule()
348  ->bubble("GNP/NPS coordinates calculated -> JOIN overlay!");
349 
351  } else {
353  coordsInfo);
354  }
355 }
356 
357 #ifdef EXTJOIN_DISCOVERY
358 void Nps::rttToNodeRpcResponse(RttToNodeResponse* response,
359  cPolymorphic* context, int rpcId, simtime_t rtt)
360 {
361  uint dim = coordBasedRouting->getXmlDimensions();
362  TransportAddress nodeToCheck = response->getPingedNode();
363  Coords tempCoords;
364  tempCoords.resize(dim);
365  for (uint i = 0; i < dim; i++) {
366  tempCoords[i] = response->getOwnCoordinates(i);
367  }
368  if (checkCoordinates(tempCoords, getNodeCoords(nodeToCheck), response->getRttToNode())) {
369  updateNodeMeasurement(nodeToCheck, -1, 0, 1);
370  } else {
371  updateNodeMeasurement(nodeToCheck, -1, 0, 0);
372  }
373  delete context;
374 }
375 #endif
376 
377 
378 bool Nps::setLandmarkSet(uint8_t howManyLM, uint8_t maxLayer,
379  std::vector<TransportAddress>* landmarkSet)
380 {
381  landmarkSet->clear();
383  uint availableLM = 0;
384  TransportAddress landmark;
385  for(it = neighborCache->neighborCache.begin(); it != neighborCache->neighborCache.end(); it++ ) {
386  if (dynamic_cast<GnpNpsCoordsInfo*>(it->second.coordsInfo) &&
387  static_cast<GnpNpsCoordsInfo*>(it->second.coordsInfo)->getLayer()
388  < maxLayer) {
389  landmark.setIp(it->first.getIp());
390  landmark.setPort(it->second.nodeRef.getPort());
391  landmarkSet->push_back(landmark);
392  availableLM++;
393  }
394  }
395  if (availableLM < howManyLM) {
396  return false;
397  } else {
398  uint i = availableLM;
399  while (i > howManyLM) {
400  uint randomNumber = (intuniform(0, landmarkSet->size()));
401  landmarkSet->erase(landmarkSet->begin() + randomNumber);
402  i--;
403  }
404  return true;
405  }
406 }
407 
409 {
410  std::vector <TransportAddress> landmarks;
411  landmarks = getLandmarks(dimensions + 1);
412 
413  simtime_t timeout = -1;
414 
415  if (landmarks.size() > 0) {
416  for (size_t i = 0; i < landmarks.size(); i++) {
417  const TransportAddress& tolm = landmarks[i];
418  sendCoordsReqCall(tolm, timeout);
419  }
421  }
422 }
423 
425  simtime_t timeout)
426 {
427  CoordsReqCall* coordReq = new CoordsReqCall("CoordsReq");
428  coordReq->setBitLength(COORDSREQCALL_L(coordReq));
430  coordReq, NULL, NO_OVERLAY_ROUTING,
431  timeout, 0, -1, this);
432  pendingRequests++;
433 }
434 
435 uint8_t Nps::computeOwnLayer(const std::vector<LandmarkDataEntry>& landmarks)
436 {
437  int8_t computedLayer = getOwnLayer();
438  for (uint i = 0; i < landmarks.size(); i++) {
439  if (computedLayer <= landmarks[i].layer) {
440  computedLayer = landmarks[i].layer + 1;
441  }
442  }
443  //setOwnLayer(computedLayer);
444  return computedLayer;
445 }
446 
447 void Nps::setOwnLayer(int8_t layer)
448 {
449  ownCoords->setLayer(layer);
450 
451  // Update in BootstrapOracle
453  thisInfo->setNpsLayer(layer);
454 
455  // Workaround against -1 ports in BS oracle
457  if (layer < maxLayer) {
460  }
461 }
462 
463 #ifdef EXTJOIN_DISCOVERY
464 bool Nps::checkCoordinates(Coords coordsOK, Coords coordsToCheck, simtime_t dist)
465 {
466  simtime_t predDist = 0.0;
467 
468  for (uint i = 0; i < coordsOK.size(); i++) {
469  predDist += pow(coordsOK[i] - coordsToCheck[i], 2);
470  }
471  simtime_t predDistLow = sqrt(SIMTIME_DBL(predDist)) * 2 * (1 - /*(coordBasedRouting->getCoordCheckPercentage() / 100)*/0.3) / 1000;
472  simtime_t predDistHigh = sqrt(SIMTIME_DBL(predDist)) * 2 * (1 + /*(coordBasedRouting->getCoordCheckPercentage() / 100)*/0.3) / 1000;
473  if (dist > predDistLow && dist < predDistHigh) {
474  return true;
475  } else {
476 // std::cout << "check of Coordinates Failed! Intervall: [ " << predDistLow << " ; " << predDistHigh << " ] and dist: " << dist << endl;
477  return false;
478  }
479 }
480 #endif
481 
482 Coords Nps::computeOwnCoordinates(const std::vector<LandmarkDataEntry>& landmarks)
483 {
484  CoordCalcFunction coordcalcf(landmarks);
485 
486  Vec_DP initCoordinates(dimensions);
487  Vec_DP bestCoordinates(dimensions);
488  Coords computedCoordinatesStdVector(dimensions);
489 
490  double bestval;
491  double resval;
492 
493  for (uint runs = 0; runs < coordCalcRuns; runs++) {
494  // start with random coordinates (-100..100 in each dim)
495  for (uint i = 0; i < dimensions; i++) {
496  initCoordinates[i] = uniform(-300, 300);
497  }
498  // compute minimum coordinates via Simplex-Downhill minimum
499  // function value is returned, coords are written into initCoordinates
500  // (call by reference)
501  resval = CoordCalcFunction::simplex_min(&coordcalcf, initCoordinates);
502  if (runs == 0 || (runs > 0 && resval < bestval) ) {
503  bestval = resval;
504  bestCoordinates = initCoordinates;
505  }
506  }
507 
508  for (uint i = 0; i < dimensions; i++) {
509  computedCoordinatesStdVector[i] = bestCoordinates[i];
510  }
511 
512  //setOwnCoordinates(computedCoordinatesStdVector);
513  return computedCoordinatesStdVector;
514 }
515 
516 std::vector<TransportAddress> Nps::getLandmarks(uint8_t howmany)
517 {
518  std::vector<TransportAddress> returnPool;
519 
520  if (howmany > globalNodeList->getLandmarkPeerSize()) {
521  throw cRuntimeError("Not enough landmarks available in network!");
522  }
523 
524  while (returnPool.size() < howmany) {
526  PeerInfo* lmInfo = globalNodeList->getPeerInfo(lm->getIp());
527  if (lmInfo->getNpsLayer() >= 0 &&
528  lmInfo->getNpsLayer() < maxLayer) {
529  // already in returnPool?
530  bool alreadyin = false;
531  for (uint8_t i = 0; i < returnPool.size(); i++) {
532  if (returnPool[i] == *lm)
533  alreadyin = true;
534  }
535  if (alreadyin == false) {
536  returnPool.push_back(*lm);
537  }
538  }
539  }
540  return returnPool;
541 }
542 
544 {
546 }
547 
548 
550 {
551  // TODO hack: coords (and so their distances) are based on one-way latencies
552  Prox temp = ownCoords->getDistance(abstractInfo);
553  temp.proximity *= 2;
554  return temp;
555 }
556 
558  uint8_t pending,
559  uint8_t sent,
560  uint8_t passed)
561 {
562  bool alreadySet = false;
563  for(uint i = 0; i < nodeMeasurements.size(); i++) {
564  if (nodeMeasurements[i].measuredNode == node && sent == 0) {
565  nodeMeasurements[i].rttsPending += pending;
566  nodeMeasurements[i].rttsSent += sent;
567  nodeMeasurements[i].coordsPassed += passed;
568  alreadySet = true;
569  i = nodeMeasurements.size();
570  } else if (nodeMeasurements[i].measuredNode == node) {
571  nodeMeasurements[i].rttsPending = pending;
572  nodeMeasurements[i].rttsSent = sent;
573  nodeMeasurements[i].coordsPassed = passed;
574  alreadySet = true;
575  i = nodeMeasurements.size();
576  }
577  }
578  if (!alreadySet) {
579  RttMeasurement newNode;
580  newNode.measuredNode = node;
581  newNode.rttsPending = pending;
582  newNode.rttsSent = sent;
583  newNode.coordsPassed = passed;
584  nodeMeasurements.push_back(newNode);
585  }
586 }
587 
589 {
590  for(uint i = 0; i < nodeMeasurements.size(); i++) {
591  if (nodeMeasurements[i].measuredNode == node) {
592 #ifdef EXTJOIN_DISCOVERY
593  delete nodeMeasurements[i].message;
594 #endif
595  nodeMeasurements.erase(nodeMeasurements.begin()+i);
596  i--;
597  }
598  }
599  if (nodeMeasurements.size() == 0) {
600  //stopNodeMeasurement();
601  }
602 }
603 
604 
606 {
607  assert(coords.size() > 1);
608  GnpNpsCoordsInfo* info = new GnpNpsCoordsInfo();
609 
610  uint8_t i;
611  for (i = 0; i < coords.size() - 1; ++i) {
612  info->setCoords(i, coords[i]);
613  }
614  info->setLayer(coords[i]);
615 
616  return info;
617 }
618 
619 
621  Vec_DP& init)
622 {
623  double accf = 0.0000001;
624  double accx = 0.0000001;
625  uint32_t nmax = 30001;
626  uint8_t dim = init.size();
627  Simplex spx(dim);
628 
629  int ihi; // Index of highest point at start of each iteration
630  Vec_DP phi(dim); // Highest point at start of each iteration.
631  double vhi; // Function value at highest point at start of each iteration.
632  double vre; // Function value at reflected point.
633  double vlo, diff; // for checking convergence.
634  uint32_t count;
635 
636  // Initialize Simplex
637  Vec_DP tmp(dim);
638  spx.functionObject = functionObject;
639  spx[0] = init;
640  for (uint8_t i = 0; i < dim; i++) {
641  tmp[i] = 1;
642  spx[i+1] = init + tmp;
643  tmp[i] = 0;
644  }
645 
646  Vec_DP debugCoords(dim);
647 
648  for (count = 1; count <= nmax; count++) {
649  /*
650  if ((count % 10000) == 0) {
651  std::cout << "running loop #" << count << " of " << nmax << endl;
652  std::cout << "diff: " << diff << std::endl;
653  std::cout << "vhi: " << vhi << std::endl;
654  std::cout << "vlo: " << vlo << std::endl;
655  debugCoords = spx[spx.low()];
656  std::cout << "Coords: " << debugCoords << std::endl;
657  }
658  */
659  ihi = spx.high(&vhi);
660  phi = spx[ihi];
661  spx.reflect();
662  vre = functionObject->f(spx[ihi]);
663  if (vre < functionObject->f(spx[spx.low()])) {
664  spx[ihi] = phi; // Undo reflection.
665  spx.reflect_exp();
666  vre = functionObject->f(spx[ihi]);
667  if (vre > functionObject->f(spx[spx.low()])) {
668  spx[ihi] = phi;
669  spx.reflect();
670  }
671  } else if (vre >= vhi) { // Equal sign important!
672  spx[ihi] = phi; // Undo reflection.
673  spx.contract();
674  if (functionObject->f(spx[ihi]) > vhi) {
675  spx[ihi] = phi; // Undo contraction.
676  spx.reduce();
677  } // else contraction ok.
678  } // else reflection ok
679 
680  spx.high(&vhi);
681  spx.low(&vlo);
682  diff = vhi - vlo;
683  if (diff < accf)
684  if (spx.size() < accx)
685  break;
686  }
687  init = spx[spx.low()];
688  return vlo;
689 }
690 
691 double CoordCalcFunction::f(const Vec_DP& initCoordinates) const
692 {
693  double sum = 0;
694  double rel_diff = 0;
695 
696  for (uint i = 0; i < landmarks.size(); i++) {
697  // Distance = RTT in ms / 2
698  double diff = SIMTIME_DBL(landmarks[i].rtt) / 2 * 1000 -
699  endnodeDistance(initCoordinates, landmarks[i]);
700 
701  if (SIMTIME_DBL(landmarks[i].rtt) != 0) {
702  rel_diff = diff / (SIMTIME_DBL(landmarks[i].rtt) / 2 * 1000);
703  } else {
704  opp_error("[CBR] RTT == 0. Node is landmark? This shouldn't happen.");
705  }
706  sum += rel_diff * rel_diff;
707  }
708  return sum;
709 }
710 
711 double CoordCalcFunction::endnodeDistance(const Vec_DP& nodeCoordinates,
712  LandmarkDataEntry landmark) const
713 {
714  double sum_of_squares = 0.0;
715  for (int i = 0; i < nodeCoordinates.size(); i++) {
716  sum_of_squares += pow(landmark.coordinates[i] - nodeCoordinates[i], 2);
717  }
718  double result = sqrt(sum_of_squares);
719  return result;
720 }
721