OverSim
SimpleUnderlayConfigurator.cc
Go to the documentation of this file.
1 //
2 // This program is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU General Public License
4 // as published by the Free Software Foundation; either version 2
5 // of the License, or (at your option) any later version.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11 //
12 // You should have received a copy of the GNU General Public License
13 // along with this program; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 //
16 
23 #include <omnetpp.h>
24 
25 #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__ANDROID__)
26 #include <malloc.h>
27 #endif
28 
29 #include <vector>
30 #include <map>
31 
32 #include <fstream>
33 
34 #include <NodeHandle.h>
35 #include "IInterfaceTable.h"
36 #include "InterfaceEntry.h"
37 #include "IPv4InterfaceData.h"
38 #include "IPv6InterfaceData.h"
39 #include "TransportAddress.h"
40 #include "IPAddressResolver.h"
41 #include <cenvir.h>
42 #include <cxmlelement.h>
43 #include "ChurnGenerator.h"
44 #include "GlobalNodeList.h"
45 #include <StringConvert.h>
46 
47 #include "SimpleUDP.h"
48 #include "SimpleTCP.h"
49 
51 
53 
54 using namespace std;
55 
57 {
58  for (uint32_t i = 0; i < nodeRecordPool.size(); ++i) {
59  //std::cout << (nodeRecordPool[i].second ? "+" : "_");
60  delete nodeRecordPool[i].first;
61  }
62  nodeRecordPool.clear();
63 }
64 
66 {
67  if (stage != MAX_STAGE_UNDERLAY)
68  return;
69 
70  // fetch some parameters
71  fixedNodePositions = par("fixedNodePositions");
72  useIPv6 = par("useIPv6Addresses");
73 
74  // set maximum coordinates and send queue length
75  fieldSize = par("fieldSize");
76  sendQueueLength = par("sendQueueLength");
77 
78  // get parameter of sourcefile's name
79  nodeCoordinateSource = par("nodeCoordinateSource");
80 
81  if (std::string(nodeCoordinateSource) != "") {
82  // check if exists and process xml-file containing coordinates
83  std::ifstream check_for_xml_file(nodeCoordinateSource);
84  if (check_for_xml_file) {
85  useXmlCoords = 1;
86 
87  EV<< "[SimpleNetConfigurator::initializeUnderlay()]\n"
88  << " Using '" << nodeCoordinateSource
89  << "' as coordinate source file" << endl;
90 
91  maxCoordinate = parseCoordFile(nodeCoordinateSource);
92  } else {
93  throw cRuntimeError("Coordinate source file not found!");
94  }
95  check_for_xml_file.close();
96  } else {
97  useXmlCoords = 0;
98  dimensions = 2; //TODO do we need this variable?
99  NodeRecord::setDim(dimensions);
100  EV << "[SimpleNetConfigurator::initializeUnderlay()]\n"
101  << " Using conventional (random) coordinates for placing nodes!\n"
102  << " (no XML coordinate source file was specified)" << endl;
103  }
104 
105  // FIXME get address from parameter
106  nextFreeAddress = 0x1000001;
107 
108  // count the overlay clients
109  overlayTerminalCount = 0;
110 
111  numCreated = 0;
112  numKilled = 0;
113 }
114 
116  bool initialize)
117 {
118  Enter_Method_Silent();
119  // derive overlay node from ned
120  cModuleType* moduleType = cModuleType::get(type.terminalType.c_str());
121 
122  std::string nameStr = "overlayTerminal";
123  if (churnGenerator.size() > 1) {
124  nameStr += "-" + convertToString<int32_t>(type.typeID);
125  }
126  cModule* node = moduleType->create(nameStr.c_str(), getParentModule(),
127  numCreated + 1, numCreated);
128 
129  std::string displayString;
130 
131  if ((type.typeID > 0) && (type.typeID <= NUM_COLORS)) {
132  ((displayString += "i=device/wifilaptop_l,")
133  += colorNames[type.typeID - 1]) += ",40;i2=block/circle_s";
134  } else {
135  displayString = "i=device/wifilaptop_l;i2=block/circle_s";
136  }
137 
138  node->finalizeParameters();
139  node->setDisplayString(displayString.c_str());
140  node->buildInside();
141  node->scheduleStart(simTime());
142 
143  for (int i = 0; i < MAX_STAGE_UNDERLAY + 1; i++) {
144  node->callInitialize(i);
145  }
146 
147  IPvXAddress addr;
148  if (useIPv6) {
149  addr = IPv6Address(0, nextFreeAddress++, 0, 0);
150  } else {
151  addr = IPAddress(nextFreeAddress++);
152  }
153 
154  int chanIndex = intuniform(0, type.channelTypesRx.size() - 1);
155  cChannelType* rxChan = cChannelType::find(type.channelTypesRx[chanIndex].c_str());
156  cChannelType* txChan = cChannelType::find(type.channelTypesTx[chanIndex].c_str());
157 
158  if (!txChan || !rxChan)
159  opp_error("Could not find Channel Type. Most likely parameter "
160  "channelTypesRx or channelTypes does not match the channels defined in "
161  "channels.ned");
162 
163  SimpleNodeEntry* entry;
164 
165  if (!useXmlCoords) {
166  entry = new SimpleNodeEntry(node, rxChan, txChan, sendQueueLength, fieldSize);
167  } else {
168  // get random unused node
169  // Changed to "predictable" volunteer start value 0 by Daniel Lienert, 05/2010 to get the same coord-sequence in every run
170  //uint32_t volunteer = 0;
171  uint32_t volunteer = intuniform(0, nodeRecordPool.size() - 1);
172  uint32_t temp = volunteer;
173  while (nodeRecordPool[volunteer].second == false) {
174  ++volunteer;
175  if (volunteer >= nodeRecordPool.size())
176  volunteer = 0;
177  // stop with errormessage if no more unused nodes available
178  if (temp == volunteer)
179  throw cRuntimeError("No unused coordinates left -> "
180  "cannot create any more nodes. "
181  "Provide %s-file with more nodes!\n", nodeCoordinateSource);
182  }
183 
184  entry = new SimpleNodeEntry(node, rxChan, txChan,
185  sendQueueLength, nodeRecordPool[volunteer].first, volunteer);
186 
187  // insert IP-address into noderecord used
188  // nodeRecordPool[volunteer].first->ip = addr;
189  nodeRecordPool[volunteer].second = false;
190  }
191 
192  SimpleUDP* simpleUdp = check_and_cast<SimpleUDP*> (node->getSubmodule("udp"));
193  simpleUdp->setNodeEntry(entry);
194  SimpleTCP* simpleTcp = dynamic_cast<SimpleTCP*> (node->getSubmodule("tcp", 0));
195  if (simpleTcp) {
196  simpleTcp->setNodeEntry(entry);
197  }
198 
199  // Add pseudo-Interface to node's interfaceTable
200  if (useIPv6) {
201  IPv6InterfaceData* ifdata = new IPv6InterfaceData;
202  ifdata->assignAddress(addr.get6(),false, 0, 0);
203  IPv6InterfaceData::AdvPrefix prefix = {addr.get6(), 64};
204  ifdata->addAdvPrefix(prefix);
205  InterfaceEntry* e = new InterfaceEntry;
206  e->setName("dummy interface");
207  e->setIPv6Data(ifdata);
208  IPAddressResolver().interfaceTableOf(node)->addInterface(e, NULL);
209  }
210  else {
211  IPv4InterfaceData* ifdata = new IPv4InterfaceData;
212  ifdata->setIPAddress(addr.get4());
213  ifdata->setNetmask(IPAddress("255.255.255.255"));
214  InterfaceEntry* e = new InterfaceEntry;
215  e->setName("dummy interface");
216  e->setIPv4Data(ifdata);
217 
218  IPAddressResolver().interfaceTableOf(node)->addInterface(e, NULL);
219  }
220 
221  // create meta information
222  SimpleInfo* info = new SimpleInfo(type.typeID, node->getId(), type.context);
223  info->setEntry(entry);
224 
225  //add node to bootstrap oracle
226  globalNodeList->addPeer(addr, info);
227 
228  // if the node was not created during startup we have to
229  // finish the initialization process manually
230  if (!initialize) {
231  for (int i = MAX_STAGE_UNDERLAY + 1; i < NUM_STAGES_ALL; i++) {
232  node->callInitialize(i);
233  }
234  }
235 
236  //show ip...
237  //TODO: migrate
238  if (fixedNodePositions && ev.isGUI()) {
239  node->getDisplayString().insertTag("p");
240  node->getDisplayString().setTagArg("p", 0, (long int)(entry->getX() * 5));
241  node->getDisplayString().setTagArg("p", 1, (long int)(entry->getY() * 5));
242  node->getDisplayString().insertTag("t", 0);
243  node->getDisplayString().setTagArg("t", 0, addr.str().c_str());
244  node->getDisplayString().setTagArg("t", 1, "l");
245  }
246 
247  overlayTerminalCount++;
248  numCreated++;
249 
250  churnGenerator[type.typeID]->terminalCount++;
251 
252  TransportAddress *address = new TransportAddress(addr);
253 
254  // update display
255  setDisplayString();
256 
257  return address;
258 }
259 
260 uint32_t SimpleUnderlayConfigurator::parseCoordFile(const char* nodeCoordinateSource)
261 {
262  cXMLElement* rootElement = ev.getXMLDocument(nodeCoordinateSource);
263 
264  // get number of dimensions from attribute of xml rootelement
265  dimensions = atoi(rootElement->getAttribute("dimensions"));
266  NodeRecord::setDim(dimensions);
267  EV << "[SimpleNetConfigurator::parseCoordFile()]\n"
268  << " using " << dimensions << " dimensions: ";
269 
270  double max_coord = 0;
271 
272  for (cXMLElement *tmpElement = rootElement->getFirstChild(); tmpElement;
273  tmpElement = tmpElement->getNextSibling()) {
274 
275  // get "ip" and "isRoot" from Attributes (not needed yet)
276  /*
277  const char* str_ip = tmpElement->getAttribute("ip");
278  int tmpIP = 0;
279  if (str_ip) sscanf(str_ip, "%x", &tmpIP);
280  bool tmpIsRoot = atoi(tmpElement->getAttribute("isroot"));
281  */
282 
283  // create tmpNode to be added to vector
284  NodeRecord* tmpNode = new NodeRecord;
285 
286  // get coords from childEntries and fill tmpNodes Array
287  int i = 0;
288  for (cXMLElement *coord = tmpElement->getFirstChild(); coord;
289  coord = coord->getNextSibling()) {
290 
291  tmpNode->coords[i] = atof(coord->getNodeValue());
292 
293  double newMax = fabs(tmpNode->coords[i]);
294  if (newMax > max_coord) {
295  max_coord = newMax;
296  }
297  i++;
298  }
299 
300  // add to vector
301  nodeRecordPool.push_back(make_pair(tmpNode, true));
302 
303  //if (nodeRecordPool.size() >= maxSize) break; //TODO use other xml lib
304  }
305 
306  EV << nodeRecordPool.size()
307  << " nodes added to vector \"nodeRecordPool\"." << endl;
308 
309 #if OMNETPP_VERSION>=0x0401
310  // free memory used for xml document
311  ev.forgetXMLDocument(nodeCoordinateSource);
312 #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__ANDROID__)
313  malloc_trim(0);
314 #endif
315 #endif
316 
317  return (uint32_t)ceil(max_coord);
318 }
319 
321 {
322  Enter_Method_Silent();
323 
324  SimpleNodeEntry* entry = NULL;
325  SimpleInfo* info;
326 
327  if (addr == NULL) {
328  addr = globalNodeList->getRandomAliveNode(type.typeID);
329 
330  if (addr == NULL) {
331  // all nodes are already prekilled
332  std::cout << "all nodes are already prekilled" << std::endl;
333  return;
334  }
335  }
336 
337  info = dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(*addr));
338 
339  if (info != NULL) {
340  entry = info->getEntry();
341  globalNodeList->setPreKilled(*addr);
342  } else {
343  opp_error("SimpleNetConfigurator: Trying to pre kill node "
344  "with nonexistant TransportAddress!");
345  }
346 
347  uint32_t effectiveType = info->getTypeID();
348  cGate* gate = entry->getUdpIPv4Gate();
349 
350  cModule* node = gate->getOwnerModule()->getParentModule();
351 
352  if (scheduledID.count(node->getId())) {
353  std::cout << "SchedID" << std::endl;
354  return;
355  }
356 
357  // remove node from bootstrap oracle
358  globalNodeList->removePeer(IPAddressResolver().addressOf(node));
359 
360  // put node into the kill list and schedule a message for final removal
361  // of the node
362  killList.push_front(IPAddressResolver().addressOf(node));
363  scheduledID.insert(node->getId());
364 
365  overlayTerminalCount--;
366  numKilled++;
367 
368  churnGenerator[effectiveType]->terminalCount--;
369 
370  // update display
371  setDisplayString();
372 
373  // inform the notification board about the removal
374  NotificationBoard* nb = check_and_cast<NotificationBoard*> (
375  node-> getSubmodule("notificationBoard"));
376  nb->fireChangeNotification(NF_OVERLAY_NODE_LEAVE);
377 
378  double random = uniform(0, 1);
379  if (random < gracefulLeaveProbability) {
380  nb->fireChangeNotification(NF_OVERLAY_NODE_GRACEFUL_LEAVE);
381  }
382 
383  cMessage* msg = new cMessage();
384  scheduleAt(simTime() + gracefulLeaveDelay, msg);
385 }
386 
388 {
389  Enter_Method_Silent();
390 
391  SimpleNodeEntry* entry = NULL;
392 
393  if (addr != NULL) {
394  SimpleInfo* info =
395  dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(*addr));
396  if (info != NULL) {
397  entry = info->getEntry();
398  } else {
399  opp_error("SimpleNetConfigurator: Trying to migrate node with "
400  "nonexistant TransportAddress!");
401  }
402  } else {
403  SimpleInfo* info = dynamic_cast<SimpleInfo*> (
404  globalNodeList-> getRandomPeerInfo(type.typeID));
405  entry = info->getEntry();
406  }
407 
408  cGate* gate = entry->getUdpIPv4Gate();
409  cModule* node = gate->getOwnerModule()->getParentModule();
410 
411  // do not migrate node that is already scheduled
412  if (scheduledID.count(node->getId()))
413  return;
414 
415  //std::cout << "migration @ " << tmp_ip << " --> " << address << std::endl;
416 
417  // FIXME use only IPv4?
418  IPvXAddress address = IPAddress(nextFreeAddress++);
419 
420  IPvXAddress tmp_ip = IPAddressResolver().addressOf(node);
421  SimpleNodeEntry* newentry;
422 
423  int chanIndex = intuniform(0, type.channelTypesRx.size() - 1);
424  cChannelType* rxChan = cChannelType::find(type.channelTypesRx[chanIndex].c_str());
425  cChannelType* txChan = cChannelType::find(type.channelTypesTx[chanIndex].c_str());
426 
427  if (!txChan || !rxChan)
428  opp_error("Could not find Channel Type. Most likely parameter "
429  "channelTypesRx or channelTypes does not match the channels defined in "
430  "channels.ned");
431 
432  if (useXmlCoords) {
433  newentry = new SimpleNodeEntry(node,
434  rxChan,
435  txChan,
436  sendQueueLength,
437  entry->getNodeRecord(), entry->getRecordIndex());
438  //newentry->getNodeRecord()->ip = address;
439  } else {
440  newentry = new SimpleNodeEntry(node, rxChan, txChan, fieldSize, sendQueueLength);
441  }
442 
443  node->bubble("I am migrating!");
444 
445  //remove node from bootstrap oracle
446  globalNodeList->killPeer(tmp_ip);
447 
448  SimpleUDP* simple = check_and_cast<SimpleUDP*> (gate->getOwnerModule());
449  simple->setNodeEntry(newentry);
450 
451  InterfaceEntry* ie = IPAddressResolver().interfaceTableOf(node)->
452  getInterfaceByName("dummy interface");
453  delete ie->ipv4Data();
454 
455  // Add pseudo-Interface to node's interfaceTable
456  IPv4InterfaceData* ifdata = new IPv4InterfaceData;
457  ifdata->setIPAddress(address.get4());
458  ifdata->setNetmask(IPAddress("255.255.255.255"));
459  ie->setIPv4Data(ifdata);
460 
461  // create meta information
462  SimpleInfo* newinfo = new SimpleInfo(type.typeID, node->getId(),
463  type.context);
464  newinfo->setEntry(newentry);
465 
466  //add node to bootstrap oracle
467  globalNodeList->addPeer(address, newinfo);
468 
469  // inform the notification board about the migration
470  NotificationBoard* nb = check_and_cast<NotificationBoard*> (
471  node->getSubmodule("notificationBoard"));
472  nb->fireChangeNotification(NF_OVERLAY_TRANSPORTADDRESS_CHANGED);
473 }
474 
476 {
477  Enter_Method_Silent();
478 
479  // get next scheduled node and remove it from the kill list
480  IPvXAddress addr = killList.back();
481  killList.pop_back();
482 
483  SimpleNodeEntry* entry = NULL;
484 
485  SimpleInfo* info =
486  dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(addr));
487 
488  if (info != NULL) {
489  entry = info->getEntry();
490  } else {
491  throw cRuntimeError("SimpleUnderlayConfigurator: Trying to kill "
492  "node with unknown TransportAddress!");
493  }
494 
495  cGate* gate = entry->getUdpIPv4Gate();
496  cModule* node = gate->getOwnerModule()->getParentModule();
497 
498  if (useXmlCoords) {
499  nodeRecordPool[entry->getRecordIndex()].second = true;
500  }
501 
502  scheduledID.erase(node->getId());
503  globalNodeList->killPeer(addr);
504 
505  InterfaceEntry* ie = IPAddressResolver().interfaceTableOf(node)->
506  getInterfaceByName("dummy interface");
507  delete ie->ipv4Data();
508 
509  node->callFinish();
510  node->deleteModule();
511 
512  delete msg;
513 }
514 
516 {
517  // Updates the statistics display string.
518  char buf[80];
519  sprintf(buf, "%i overlay terminals", overlayTerminalCount);
520  getDisplayString().setTagArg("t", 0, buf);
521 }
522 
524 {
525  // statistics
526  recordScalar("Terminals added", numCreated);
527  recordScalar("Terminals removed", numKilled);
528 
529  if (!isInInitPhase()) {
530  struct timeval now, diff;
531  gettimeofday(&now, NULL);
532  timersub(&now, &initFinishedTime, &diff);
533  printf("Simulation time: %li.%06li\n", diff.tv_sec, diff.tv_usec);
534  }
535 }
536 
537 // new functions for behaviour generator:
538 
539 IPvXAddress SimpleUnderlayConfigurator::migrateNode(NodeType type, IPvXAddress addr,
540  const BaseLocation& locID)
541 {
542  Enter_Method_Silent();
543 
544  SimpleNodeEntry* entry = NULL;
545 
546  SimpleInfo* info =
547  dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(addr));
548  if (info != NULL) {
549  entry = info->getEntry();
550  } else {
551  opp_error("SimpleNetConfigurator: Trying to migrate node with "
552  "nonexistent TransportAddress!");
553  }
554 
555  const NodeRecord* location = dynamic_cast<const NodeRecord*>(&locID);
556  entry->setX(location->coords[0]);
557  entry->setY(location->coords[1]);
558 
559  cGate* gate = entry->getUdpIPv4Gate();
560  cModule* node = gate->getOwnerModule()->getParentModule();
561 
562  // do not migrate node that is already scheduled
563  if (scheduledID.count(node->getId()))
564  return addr;
565 
566  // FIXME use only IPv4?
567  IPvXAddress address = IPAddress(nextFreeAddress++);
568  EV << addr << " migrates to ";
569  EV << address << "!" << endl;
570 
571  SimpleNodeEntry* newentry;
572 
573  int chanIndex = intuniform(0, type.channelTypesRx.size() - 1);
574  cChannelType* rxChan = cChannelType::find(type.channelTypesRx[chanIndex].c_str());
575  cChannelType* txChan = cChannelType::find(type.channelTypesTx[chanIndex].c_str());
576 
577  if (!txChan || !rxChan)
578  opp_error("Could not find Channel Type. Most likely parameter "
579  "channelTypesRx or channelTypes does not match the channels defined in "
580  "channels.ned");
581 
582  if (useXmlCoords) {
583  newentry = new SimpleNodeEntry(node,
584  rxChan,
585  txChan,
586  sendQueueLength,
587  entry->getNodeRecord(), entry->getRecordIndex());
588  } else {
589  newentry = new SimpleNodeEntry(node, rxChan, txChan, fieldSize, sendQueueLength);
590  }
591 
592  node->bubble("I am migrating!");
593 
594  //remove node from bootstrap oracle
595  NodeHandle* peer = globalNodeList->getNodeHandle(addr);
596  NodeHandle registrationPeer;
597 
598  if (peer != NULL) {
599  registrationPeer = *peer;
600  }
601 
602  globalNodeList->killPeer(addr);
603 
604  SimpleUDP* simple = check_and_cast<SimpleUDP*> (gate->getOwnerModule());
605  simple->setNodeEntry(newentry);
606 
607  InterfaceEntry* ie = IPAddressResolver().interfaceTableOf(node)->
608  getInterfaceByName("dummy interface");
609  delete ie->ipv4Data();
610 
611  // Add pseudo-Interface to node's interfaceTable
612  IPv4InterfaceData* ifdata = new IPv4InterfaceData;
613  ifdata->setIPAddress(address.get4());
614  ifdata->setNetmask(IPAddress("255.255.255.255"));
615  ie->setIPv4Data(ifdata);
616 
617  // create meta information
618  SimpleInfo* newinfo = new SimpleInfo(type.typeID, node->getId(),
619  type.context);
620  newinfo->setEntry(newentry);
621 
622  //add node to bootstrap oracle
623  globalNodeList->addPeer(address, newinfo);
624 
625  if (peer != NULL){
626  registrationPeer.setIp(address);
627  globalNodeList->registerPeer(registrationPeer);
628  }
629 
630 // check_and_cast<>BaseRpc>(simulation.getModule(newinfo->getModuleID())->getSubmodule("tier1"));
631  // inform the notification board about the migration
632  NotificationBoard* nb = check_and_cast<NotificationBoard*> (
633  node->getSubmodule("notificationBoard"));
634  nb->fireChangeNotification(NF_OVERLAY_TRANSPORTADDRESS_CHANGED);
635 
636  return address;
637 }
638 
640  NodeRecord a = dynamic_cast<const NodeRecord&>(IDa);
641  NodeRecord b = dynamic_cast<const NodeRecord&>(IDb);
642  return sqrt( pow((a.coords[0] - b.coords[0]), 2)
643  + pow((a.coords[1] - b.coords[1]), 2) );
644 }
645 
647  const NodeRecord* tempLoc = dynamic_cast<const NodeRecord*>(&ID);
648  NodeRecord* ret = new NodeRecord();
649 
650  radius = uniform (0.3, 1, 0) * radius; // scales the radius randomly
651  double angle = uniform (0, 2 *M_PI, 0); // random angle
652 
653  ret->coords[0] = cos(angle)*radius + tempLoc->coords[0];
654  ret->coords[1] = sin(angle)*radius + tempLoc->coords[1];
655  return ret;
656 }
657 
659  SimpleInfo* info = dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(addr));
660  BaseLocation* ret = info->getEntry()->getNodeRecord();
661  return ret;
662 }