SimpleUnderlayConfigurator.cc

Go to the documentation of this file.
00001 //
00002 // This program is free software; you can redistribute it and/or
00003 // modify it under the terms of the GNU General Public License
00004 // as published by the Free Software Foundation; either version 2
00005 // of the License, or (at your option) any later version.
00006 //
00007 // This program is distributed in the hope that it will be useful,
00008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010 // GNU General Public License for more details.
00011 //
00012 // You should have received a copy of the GNU General Public License
00013 // along with this program; if not, write to the Free Software
00014 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00015 //
00016 
00023 #include <omnetpp.h>
00024 #include <malloc.h>
00025 #include <vector>
00026 #include <map>
00027 
00028 #include <fstream>
00029 
00030 #include <NodeHandle.h>
00031 #include "IInterfaceTable.h"
00032 #include "InterfaceEntry.h"
00033 #include "IPv4InterfaceData.h"
00034 #include "TransportAddress.h"
00035 #include "IPAddressResolver.h"
00036 #include <cenvir.h>
00037 #include <cxmlelement.h>
00038 #include "ChurnGenerator.h"
00039 #include "GlobalNodeList.h"
00040 #include <StringConvert.h>
00041 
00042 #include "SimpleUDP.h"
00043 
00044 #include "SimpleUnderlayConfigurator.h"
00045 
00046 Define_Module(SimpleUnderlayConfigurator);
00047 
00048 using namespace std;
00049 
00050 SimpleUnderlayConfigurator::~SimpleUnderlayConfigurator()
00051 {
00052     for (uint32_t i = 0; i < nodeRecordPool.size(); ++i) {
00053         //std::cout << (nodeRecordPool[i].second ? "+" : "_");
00054         delete nodeRecordPool[i].first;
00055     }
00056     nodeRecordPool.clear();
00057 }
00058 
00059 void SimpleUnderlayConfigurator::initializeUnderlay(int stage)
00060 {
00061     if (stage != MAX_STAGE_UNDERLAY)
00062         return;
00063 
00064     // fetch some parameters
00065     fixedNodePositions = par("fixedNodePositions");
00066 
00067     // set maximum coordinates and send queue length
00068     fieldSize = par("fieldSize");
00069     sendQueueLength = par("sendQueueLength");
00070 
00071     // get parameter of sourcefile's name
00072     nodeCoordinateSource = par("nodeCoordinateSource");
00073 
00074     if (std::string(nodeCoordinateSource) != "") {
00075         // check if exists and process xml-file containing coordinates
00076         std::ifstream check_for_xml_file(nodeCoordinateSource);
00077         if (check_for_xml_file) {
00078             useXmlCoords = 1;
00079 
00080             EV<< "[SimpleNetConfigurator::initializeUnderlay()]\n"
00081             << "    Using '" << nodeCoordinateSource
00082             << "' as coordinate source file" << endl;
00083 
00084             maxCoordinate = parseCoordFile(nodeCoordinateSource);
00085         } else {
00086             throw cRuntimeError("Coordinate source file not found!");
00087         }
00088         check_for_xml_file.close();
00089     } else {
00090         useXmlCoords = 0;
00091         dimensions = 2; //TODO do we need this variable?
00092         NodeRecord::setDim(dimensions);
00093         EV << "[SimpleNetConfigurator::initializeUnderlay()]\n"
00094         << "    Using conventional (random) coordinates for placing nodes!\n"
00095         << "    (no XML coordinate source file was specified)" << endl;
00096     }
00097 
00098     // FIXME get address from parameter
00099     nextFreeAddress = 0x1000001;
00100 
00101     // count the overlay clients
00102     overlayTerminalCount = 0;
00103 
00104     numCreated = 0;
00105     numKilled = 0;
00106 }
00107 
00108 TransportAddress* SimpleUnderlayConfigurator::createNode(NodeType type,
00109                                                          bool initialize)
00110 {
00111     Enter_Method_Silent();
00112     // derive overlay node from ned
00113     cModuleType* moduleType = cModuleType::get(type.terminalType.c_str());
00114 
00115     std::string nameStr = "overlayTerminal";
00116     if( churnGenerator.size() > 1 ){
00117         nameStr += "-" + convertToString<uint32_t>(type.typeID);
00118     }
00119     cModule* node = moduleType->create(nameStr.c_str(), getParentModule(),
00120                                        numCreated + 1, numCreated);
00121 
00122     node->par("overlayType").setStringValue(type.overlayType.c_str());
00123     node->par("tier1Type").setStringValue(type.tier1Type.c_str());
00124     node->par("tier2Type").setStringValue(type.tier2Type.c_str());
00125     node->par("tier3Type").setStringValue(type.tier3Type.c_str());
00126 
00127     std::string displayString;
00128 
00129     if ((type.typeID > 1) && (type.typeID <= (NUM_COLORS + 1))) {
00130         ((displayString += "i=device/wifilaptop_l,") += colorNames[type.typeID
00131                 - 2]) += ",40;i2=block/circle_s";
00132     } else {
00133         displayString = "i=device/wifilaptop_l;i2=block/circle_s";
00134     }
00135 
00136     node->finalizeParameters();
00137     node->setDisplayString(displayString.c_str());
00138     node->buildInside();
00139     node->scheduleStart(simTime());
00140 
00141     for (int i = 0; i < MAX_STAGE_UNDERLAY + 1; i++) {
00142         node->callInitialize(i);
00143     }
00144 
00145     // FIXME use only IPv4?
00146     IPvXAddress addr = IPAddress(nextFreeAddress++);
00147 
00148     int chanIndex = intuniform(0, type.channelTypesRx.size() - 1);
00149     cChannelType* rxChan = cChannelType::find(type.channelTypesRx[chanIndex].c_str());
00150     cChannelType* txChan = cChannelType::find(type.channelTypesTx[chanIndex].c_str());
00151 
00152     if (!txChan || !rxChan)
00153          opp_error("Could not find Channel Type. Most likely parameter "
00154             "channelTypesRx or channelTypes does not match the channels defined in "
00155              "channels.ned");
00156 
00157     SimpleNodeEntry* entry;
00158 
00159     if (!useXmlCoords) {
00160         entry = new SimpleNodeEntry(node, rxChan, txChan, sendQueueLength, fieldSize);
00161     } else {
00162         //get random unused node
00163         uint32_t volunteer = intuniform(0, nodeRecordPool.size() - 1);
00164         uint32_t temp = volunteer;
00165         while (nodeRecordPool[volunteer].second == false) {
00166             ++volunteer;
00167             if (volunteer >= nodeRecordPool.size())
00168                 volunteer = 0;
00169             // stop with errormessage if no more unused nodes available
00170             if (temp == volunteer)
00171                 throw cRuntimeError("No unused coordinates left -> "
00172                     "cannot create any more nodes. "
00173                     "Provide %s-file with more nodes!\n", nodeCoordinateSource);
00174         }
00175 
00176          entry = new SimpleNodeEntry(node, rxChan, txChan,
00177                  sendQueueLength, nodeRecordPool[volunteer].first, volunteer);
00178 
00179         //insert IP-address into noderecord used
00180         //nodeRecordPool[volunteer].first->ip = addr;
00181         nodeRecordPool[volunteer].second = false;
00182     }
00183 
00184     SimpleUDP* simple = check_and_cast<SimpleUDP*> (node->getSubmodule("udp"));
00185     simple->setNodeEntry(entry);
00186 
00187     // Add pseudo-Interface to node's interfaceTable
00188     IPv4InterfaceData* ifdata = new IPv4InterfaceData;
00189     ifdata->setIPAddress(addr.get4());
00190     ifdata->setNetmask(IPAddress("255.255.255.255"));
00191     InterfaceEntry* e = new InterfaceEntry;
00192     e->setName("dummy interface");
00193     e->setIPv4Data(ifdata);
00194 
00195     IPAddressResolver().interfaceTableOf(node)->addInterface(e, NULL);
00196 
00197     // create meta information
00198     SimpleInfo* info = new SimpleInfo(type.typeID, node->getId(), type.context);
00199     info->setEntry(entry);
00200 
00201     //add node to bootstrap oracle
00202     globalNodeList->addPeer(addr, info);
00203 
00204     // if the node was not created during startup we have to
00205     // finish the initialization process manually
00206     if (!initialize) {
00207         for (int i = MAX_STAGE_UNDERLAY + 1; i < NUM_STAGES_ALL; i++) {
00208             node->callInitialize(i);
00209         }
00210     }
00211 
00212     //show ip...
00213     //TODO: migrate
00214     if (fixedNodePositions && ev.isGUI()) {
00215         node->getDisplayString().insertTag("p");
00216         node->getDisplayString().setTagArg("p", 0, (long int)(entry->getX() * 5));
00217         node->getDisplayString().setTagArg("p", 1, (long int)(entry->getY() * 5));
00218         node->getDisplayString().insertTag("t", 0);
00219         node->getDisplayString().setTagArg("t", 0, addr.str().c_str());
00220         node->getDisplayString().setTagArg("t", 1, "l");
00221     }
00222 
00223     overlayTerminalCount++;
00224     numCreated++;
00225 
00226     churnGenerator[type.typeID - 1]->terminalCount++;
00227 
00228     TransportAddress *address = new TransportAddress(addr);
00229 
00230     // update display
00231     setDisplayString();
00232 
00233     return address;
00234 }
00235 
00236 uint32_t SimpleUnderlayConfigurator::parseCoordFile(const char* nodeCoordinateSource)
00237 {
00238     cXMLElement* rootElement = ev.getXMLDocument(nodeCoordinateSource);
00239 
00240     // get number of dimensions from attribute of xml rootelement
00241     dimensions = atoi(rootElement->getAttribute("dimensions"));
00242     NodeRecord::setDim(dimensions);
00243     EV << "[SimpleNetConfigurator::parseCoordFile()]\n"
00244        << "    using " << dimensions << " dimensions: ";
00245 
00246     double max_coord = 0;
00247 
00248     for (cXMLElement *tmpElement = rootElement->getFirstChild(); tmpElement;
00249          tmpElement = tmpElement->getNextSibling()) {
00250 
00251         // get "ip" and "isRoot" from Attributes (not needed yet)
00252       /*
00253        const char* str_ip = tmpElement->getAttribute("ip");
00254        int tmpIP = 0;
00255        if (str_ip) sscanf(str_ip, "%x", &tmpIP);
00256        bool tmpIsRoot = atoi(tmpElement->getAttribute("isroot"));
00257        */
00258 
00259         // create tmpNode to be added to vector
00260         NodeRecord* tmpNode = new NodeRecord;
00261 
00262         // get coords from childEntries and fill tmpNodes Array
00263         int i = 0;
00264         for (cXMLElement *coord = tmpElement->getFirstChild(); coord;
00265              coord = coord->getNextSibling()) {
00266 
00267             tmpNode->coords[i] = atof(coord->getNodeValue());
00268 
00269             double newMax = fabs(tmpNode->coords[i]);
00270             if (newMax > max_coord) {
00271                max_coord = newMax;
00272             }
00273             i++;
00274         }
00275 
00276         // add to vector
00277         nodeRecordPool.push_back(make_pair(tmpNode, true));
00278 
00279         //if (nodeRecordPool.size() >= maxSize) break; //TODO use other xml lib
00280     }
00281 
00282     EV << nodeRecordPool.size()
00283        << " nodes added to vector \"nodeRecordPool\"." << endl;
00284 
00285     // free memory used for xml document (not needed any more)
00286     // disabled for now, since OMNeT++ keeps a cache for parsed XML
00287     // documents, which leads to a SEGV, if the same document is parsed twice  
00288 #if 0    
00289     delete rootElement;
00290     malloc_trim(0);
00291 #endif
00292     
00293     return (uint32_t)ceil(max_coord);
00294 }
00295 
00296 void SimpleUnderlayConfigurator::preKillNode(NodeType type, TransportAddress* addr)
00297 {
00298     Enter_Method_Silent();
00299 
00300     SimpleNodeEntry* entry = NULL;
00301     SimpleInfo* info;
00302 
00303     if (addr == NULL) {
00304         addr = globalNodeList->getRandomAliveNode(type.typeID);
00305 
00306         if (addr == NULL) {
00307             // all nodes are already prekilled
00308             std::cout << "all nodes are already prekilled" << std::endl;
00309             return;
00310         }
00311     }
00312 
00313     info = dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(*addr));
00314 
00315     if (info != NULL) {
00316         entry = info->getEntry();
00317         globalNodeList->setPreKilled(*addr);
00318     } else {
00319         opp_error("SimpleNetConfigurator: Trying to pre kill node "
00320                   "with nonexistant TransportAddress!");
00321     }
00322 
00323     uint32_t effectiveType = info->getTypeID();
00324     cGate* gate = entry->getGate();
00325 
00326     cModule* node = gate->getOwnerModule()->getParentModule();
00327 
00328     if (scheduledID.count(node->getId())) {
00329         std::cout << "SchedID" << std::endl;
00330         return;
00331     }
00332 
00333     // remove node from bootstrap oracle
00334     globalNodeList->removePeer(IPAddressResolver().addressOf(node));
00335 
00336     // put node into the kill list and schedule a message for final removal
00337     // of the node
00338     killList.push_front(IPAddressResolver().addressOf(node));
00339     scheduledID.insert(node->getId());
00340 
00341     overlayTerminalCount--;
00342     numKilled++;
00343 
00344     churnGenerator[effectiveType - 1]->terminalCount--;
00345 
00346     // update display
00347     setDisplayString();
00348 
00349     // inform the notification board about the removal
00350     NotificationBoard* nb = check_and_cast<NotificationBoard*> (
00351                              node-> getSubmodule("notificationBoard"));
00352     nb->fireChangeNotification(NF_OVERLAY_NODE_LEAVE);
00353 
00354     double random = uniform(0, 1);
00355     if (random < gracefulLeaveProbability) {
00356         nb->fireChangeNotification(NF_OVERLAY_NODE_GRACEFUL_LEAVE);
00357     }
00358 
00359     cMessage* msg = new cMessage();
00360     scheduleAt(simTime() + gracefulLeaveDelay, msg);
00361 }
00362 
00363 void SimpleUnderlayConfigurator::migrateNode(NodeType type, TransportAddress* addr)
00364 {
00365     Enter_Method_Silent();
00366 
00367     SimpleNodeEntry* entry = NULL;
00368 
00369     if (addr != NULL) {
00370         SimpleInfo* info =
00371               dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(*addr));
00372         if (info != NULL) {
00373             entry = info->getEntry();
00374         } else {
00375             opp_error("SimpleNetConfigurator: Trying to migrate node with "
00376                       "nonexistant TransportAddress!");
00377         }
00378     } else {
00379         SimpleInfo* info = dynamic_cast<SimpleInfo*> (
00380                 globalNodeList-> getRandomPeerInfo(type.typeID));
00381         entry = info->getEntry();
00382     }
00383 
00384     cGate* gate = entry->getGate();
00385     cModule* node = gate->getOwnerModule()->getParentModule();
00386 
00387     // do not migrate node that is already scheduled
00388     if (scheduledID.count(node->getId()))
00389         return;
00390 
00391     //std::cout << "migration @ " << tmp_ip << " --> " << address << std::endl;
00392 
00393     // FIXME use only IPv4?
00394     IPvXAddress address = IPAddress(nextFreeAddress++);
00395 
00396     IPvXAddress tmp_ip = IPAddressResolver().addressOf(node);
00397     SimpleNodeEntry* newentry;
00398 
00399     int chanIndex = intuniform(0, type.channelTypesRx.size() - 1);
00400     cChannelType* rxChan = cChannelType::find(type.channelTypesRx[chanIndex].c_str());
00401     cChannelType* txChan = cChannelType::find(type.channelTypesTx[chanIndex].c_str());
00402 
00403     if (!txChan || !rxChan)
00404          opp_error("Could not find Channel Type. Most likely parameter "
00405             "channelTypesRx or channelTypes does not match the channels defined in "
00406              "channels.ned");
00407 
00408     if (useXmlCoords) {
00409        newentry = new SimpleNodeEntry(node,
00410                                       rxChan,
00411                                       txChan,
00412                                       sendQueueLength,
00413                                       entry->getNodeRecord(), entry->getRecordIndex());
00414         //newentry->getNodeRecord()->ip = address;
00415     } else {
00416         newentry = new SimpleNodeEntry(node, rxChan, txChan, fieldSize, sendQueueLength);
00417     }
00418 
00419     node->bubble("I am migrating!");
00420 
00421     //remove node from bootstrap oracle
00422     globalNodeList->killPeer(tmp_ip);
00423 
00424     SimpleUDP* simple = check_and_cast<SimpleUDP*> (gate->getOwnerModule());
00425     simple->setNodeEntry(newentry);
00426 
00427     InterfaceEntry* ie = IPAddressResolver().interfaceTableOf(node)->
00428                                       getInterfaceByName("dummy interface");
00429     delete ie->ipv4Data();
00430 
00431     // Add pseudo-Interface to node's interfaceTable
00432     IPv4InterfaceData* ifdata = new IPv4InterfaceData;
00433     ifdata->setIPAddress(address.get4());
00434     ifdata->setNetmask(IPAddress("255.255.255.255"));
00435     ie->setIPv4Data(ifdata);
00436 
00437     // create meta information
00438     SimpleInfo* newinfo = new SimpleInfo(type.typeID, node->getId(),
00439                                          type.context);
00440     newinfo->setEntry(newentry);
00441 
00442     //add node to bootstrap oracle
00443     globalNodeList->addPeer(address, newinfo);
00444 
00445     // inform the notification board about the migration
00446     NotificationBoard* nb = check_and_cast<NotificationBoard*> (
00447                                       node->getSubmodule("notificationBoard"));
00448     nb->fireChangeNotification(NF_OVERLAY_TRANSPORTADDRESS_CHANGED);
00449 }
00450 
00451 void SimpleUnderlayConfigurator::handleTimerEvent(cMessage* msg)
00452 {
00453     Enter_Method_Silent();
00454 
00455     // get next scheduled node and remove it from the kill list
00456     IPvXAddress addr = killList.back();
00457     killList.pop_back();
00458 
00459     SimpleNodeEntry* entry = NULL;
00460 
00461     SimpleInfo* info =
00462             dynamic_cast<SimpleInfo*> (globalNodeList->getPeerInfo(addr));
00463 
00464     if (info != NULL) {
00465         entry = info->getEntry();
00466     } else {
00467         throw cRuntimeError("SimpleNetConfigurator: Trying to kill node with "
00468                             "unknown TransportAddress!");
00469     }
00470 
00471     cGate* gate = entry->getGate();
00472     cModule* node = gate->getOwnerModule()->getParentModule();
00473 
00474     if (useXmlCoords) {
00475         nodeRecordPool[entry->getRecordIndex()].second = true;
00476     }
00477 
00478     scheduledID.erase(node->getId());
00479     globalNodeList->killPeer(addr);
00480 
00481     InterfaceEntry* ie = IPAddressResolver().interfaceTableOf(node)->
00482                                          getInterfaceByName("dummy interface");
00483     delete ie->ipv4Data();
00484 
00485     node->callFinish();
00486     node->deleteModule();
00487 
00488     delete msg;
00489 }
00490 
00491 void SimpleUnderlayConfigurator::setDisplayString()
00492 {
00493     // Updates the statistics display string.
00494     char buf[80];
00495     sprintf(buf, "%i overlay terminals", overlayTerminalCount);
00496     getDisplayString().setTagArg("t", 0, buf);
00497 }
00498 
00499 void SimpleUnderlayConfigurator::finishUnderlay()
00500 {
00501     // statistics
00502     recordScalar("Terminals added", numCreated);
00503     recordScalar("Terminals removed", numKilled);
00504 
00505     if (!isInInitPhase()) {
00506         struct timeval now, diff;
00507         gettimeofday(&now, NULL);
00508         timersub(&now, &initFinishedTime, &diff);
00509         printf("Simulation time: %li.%06li\n", diff.tv_sec, diff.tv_usec);
00510     }
00511 }
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3