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