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

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