I3BaseApp.cc

Go to the documentation of this file.
00001 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00002 //
00003 // This program is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU General Public License
00005 // as published by the Free Software Foundation; either version 2
00006 // of the License, or (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00016 //
00017 
00023 #include <omnetpp.h>
00024 #include <IPAddressResolver.h>
00025 #include <GlobalNodeListAccess.h>
00026 #include <InitStages.h>
00027 #include <NotificationBoard.h>
00028 #include <UnderlayConfigurator.h>
00029 #include <UDPControlInfo_m.h>
00030 #include <NodeHandle.h>
00031 #include <BootstrapList.h>
00032 
00033 #include "I3Trigger.h"
00034 #include "I3IdentifierStack.h"
00035 #include "I3Message.h"
00036 #include "I3BaseApp.h"
00037 
00038 #include <iostream>
00039 #include <sstream>
00040 #include <cfloat>
00041 
00042 using namespace std;
00043 
00044 
00045 I3BaseApp::I3CachedServer::I3CachedServer() :
00046         lastReply(0),
00047         roundTripTime(MAXTIME)
00048 {
00049 }
00050 
00051 std::ostream &operator<<(std::ostream &os, const I3BaseApp::I3CachedServer &server) {
00052     os << server.address << " rt=" << server.roundTripTime;
00053     return os;
00054 }
00055 
00056 
00057 
00058 I3BaseApp::I3BaseApp()
00059 {
00060 }
00061 
00062 I3BaseApp::~I3BaseApp()
00063 {
00064 }
00065 
00066 int I3BaseApp::numInitStages() const
00067 {
00068     return MAX_STAGE_APP + 1;
00069 }
00070 
00071 void I3BaseApp::initialize(int stage)
00072 {
00073     if (stage != MIN_STAGE_APP) return;
00074 
00075     nodeIPAddress = IPAddressResolver().addressOf(getParentModule());
00076 
00077     bindToPort(par("clientPort"));
00078     /*    NotificationBoardAccess().get()->subscribe(this, NF_HOSTPOSITION_BEFOREUPDATE);
00079         NotificationBoardAccess().get()->subscribe(this, NF_HOSTPOSITION_UPDATED);*/
00080 
00081     getDisplayString().setTagArg("i", 0, "i3c");
00082     getParentModule()->getDisplayString().removeTag("i2");
00083 
00084     if (int(par("bootstrapTime")) >= int(par("initTime"))) {
00085         opp_error("Parameter bootstrapTime must be smaller than initTime");
00086     }
00087 
00088     bootstrapTimer = new cMessage();
00089     scheduleAt(simTime() + int(par("bootstrapTime")), bootstrapTimer);
00090 
00091     initializeTimer = new cMessage();
00092     scheduleAt(simTime() + int(par("initTime")), initializeTimer);
00093 
00094     numSent = 0;
00095     sentBytes = 0;
00096     numReceived = 0;
00097     receivedBytes = 0;
00098     numIsolations = 0;
00099     mobilityInStages = false;
00100 
00101     WATCH(nodeIPAddress);
00102     WATCH(numSent);
00103     WATCH(sentBytes);
00104     WATCH(numReceived);
00105     WATCH(receivedBytes);
00106     WATCH(numIsolations);
00107 
00108 
00109     WATCH_SET(insertedTriggers);
00110     WATCH(gateway);
00111     WATCH_MAP(samplingCache);
00112     WATCH_MAP(identifierCache);
00113 
00114     initializeApp(stage);
00115 }
00116 
00117 void I3BaseApp::initializeApp(int stage)
00118 {
00119 }
00120 
00121 void I3BaseApp::bootstrapI3()
00122 {
00123     I3IPAddress myAddress(nodeIPAddress, par("clientPort"));
00124 
00125     // TODO: use BootstrapList instead of GlobalNodeList
00126     const NodeHandle handle = GlobalNodeListAccess().get()->getBootstrapNode();
00127     gateway.address = I3IPAddress(handle.getAddress(), par("serverPort"));
00128 
00129     int cacheSize = par("cacheSize");
00130     for (int i = 0; i < cacheSize; i++) {
00131         I3Identifier id;
00132 
00133         id.createRandomKey();
00134 
00135         ostringstream os;
00136         os << myAddress << " sample" << i;
00137         id.setName(os.str());
00138 
00139         samplingCache[id] = I3CachedServer(); // placeholder
00140 
00141         insertTrigger(id, false);
00142     }
00143 
00144     refreshTriggersTimer = new cMessage();
00145     refreshTriggersTime = par("triggerRefreshTime");
00146     scheduleAt(simTime() + truncnormal(refreshTriggersTime, refreshTriggersTime / 10),
00147                refreshTriggersTimer);
00148 
00149     refreshSamplesTimer = new cMessage();
00150     refreshSamplesTime = par("sampleRefreshTime");
00151     scheduleAt(simTime() + truncnormal(refreshSamplesTime, refreshSamplesTime / 10),
00152                refreshSamplesTimer);
00153 }
00154 
00155 void I3BaseApp::initializeI3()
00156 {
00157 
00158 }
00159 
00160 void I3BaseApp::handleMessage(cMessage *msg)
00161 {
00162     if (msg->isSelfMessage()) {
00163         if (msg == bootstrapTimer) {
00164             bootstrapI3();
00165             delete msg;
00166             bootstrapTimer = 0;
00167         } else if (msg == initializeTimer)  {
00168             initializeI3();
00169             delete msg;
00170             initializeTimer = 0;
00171         } else if (msg == refreshTriggersTimer) {
00172             refreshTriggers();
00173             scheduleAt(simTime() + truncnormal(refreshTriggersTime, refreshTriggersTime / 10),
00174                        refreshTriggersTimer);
00175         } else if (msg == refreshSamplesTimer) {
00176             refreshSamples();
00177             scheduleAt(simTime() + truncnormal(refreshSamplesTime, refreshSamplesTime / 10),
00178                        refreshSamplesTimer);
00179         } else {
00180             handleTimerEvent(msg);
00181         }
00182     } else if (msg->arrivedOn("udpIn")) {
00183         handleUDPMessage(msg);
00184     } else {
00185         delete msg;
00186     }
00187 }
00188 
00189 void I3BaseApp::deliver(I3Trigger &matchingTrigger, I3IdentifierStack &stack, cPacket *msg)
00190 {
00191     delete msg;
00192 }
00193 
00194 void I3BaseApp::handleTimerEvent(cMessage *msg)
00195 {
00196     delete msg;
00197 }
00198 
00199 void I3BaseApp::handleUDPMessage(cMessage *msg)
00200 {
00201     I3Message *i3msg;
00202 
00203     i3msg = dynamic_cast<I3Message*>(msg);
00204     if (i3msg) {
00205         switch (i3msg->getType()) {
00206         case SEND_PACKET:
00207         {
00208             I3SendPacketMessage *smsg;
00209 
00210             smsg = check_and_cast<I3SendPacketMessage*>(msg);
00211             numReceived++;
00212             receivedBytes += smsg->getByteLength();
00213 
00214             /* deliver to app */
00215             cPacket *newMessage = smsg->decapsulate();
00216             deliver(smsg->getMatchedTrigger(), smsg->getIdentifierStack(), newMessage);
00217 
00218             break;
00219         }
00220         case QUERY_REPLY:
00221         {
00222             I3QueryReplyMessage *pmsg;
00223             pmsg = check_and_cast<I3QueryReplyMessage*>(msg);
00224             I3Identifier &id = pmsg->getIdentifier();
00225 
00226             identifierCache[id].address = pmsg->getSource();
00227             identifierCache[id].lastReply = simTime();
00228             identifierCache[id].roundTripTime = simTime() - pmsg->getSendingTime();
00229 
00230             if (samplingCache.count(id) != 0) {
00231                 samplingCache[id] = identifierCache[id];
00232             }
00233             break;
00234         }
00235         default:
00236             /* shouldn't get here */
00237             break;
00238         }
00239     }
00240     delete msg;
00241 }
00242 
00243 void I3BaseApp::sendToI3(I3Message *msg)
00244 {
00245     sendThroughUDP(msg, gateway.address);
00246 }
00247 
00248 void I3BaseApp::sendThroughUDP(cMessage *msg, const I3IPAddress &add)
00249 {
00250     msg->removeControlInfo();
00251     msg->setKind(UDP_C_DATA);
00252 
00253     UDPControlInfo* udpControlInfo = new UDPControlInfo();
00254     udpControlInfo->setSrcAddr(nodeIPAddress);
00255     udpControlInfo->setSrcPort(par("clientPort"));
00256 
00257     udpControlInfo->setDestAddr(add.getAddress());
00258     udpControlInfo->setDestPort(add.getPort());
00259 
00260     msg->setControlInfo(udpControlInfo);
00261     send(msg, "udpOut");
00262 }
00263 
00264 void I3BaseApp::refreshTriggers()
00265 {
00266     I3IPAddress myAddress(nodeIPAddress, par("clientPort"));
00267     map<I3Identifier, I3CachedServer>::iterator mit;
00268 
00269 
00270     // pick fastest I3 server as gateway
00271     int serverTimeout = par("serverTimeout");
00272     gateway.roundTripTime = serverTimeout;
00273     I3Identifier gatewayId;
00274     for (mit = samplingCache.begin(); mit != samplingCache.end(); mit++) {
00275         if (gateway.roundTripTime > mit->second.roundTripTime) {
00276             gatewayId = mit->first;
00277             gateway = mit->second;
00278         }
00279     }
00280 
00281     // check if gateway has timeout'ed
00282     if (simTime() - gateway.lastReply >= serverTimeout) {
00283         // We have a small problem here: if the fastest server has timeout,
00284         // that means the previous gateway had stopped responding some time before and no triggers were refreshed.
00285         // Since all servers have timeout'ed by now and we can't trust return times, pick a random server and hope that one is alive.
00286         int random = intrand(samplingCache.size()), i;
00287 
00288         EV << "I3BaseApp::refreshTriggers()]\n"
00289            << "    Gateway timeout at " << nodeIPAddress
00290            << ", time " << simTime()
00291            << "; expired gateway is " << gateway << "(" << gatewayId << ") "
00292            << " with last reply at " << gateway.lastReply
00293            << endl;
00294 
00295         for (i = 0, mit = samplingCache.begin(); i < random; i++, mit++);
00296         gateway = mit->second;
00297         EV << "I3BaseApp::refreshTriggers()]\n"
00298            << "    New gateway for " << nodeIPAddress << " is " << gateway
00299            << endl;
00300 
00301         if (gateway.roundTripTime > 2 * serverTimeout) {
00302             EV << "I3BaseApp::refreshTriggers()]\n"
00303                << "    New gateway's (" << gateway << ") rtt for " << nodeIPAddress
00304                << " too high... marking as isolated!"
00305                << endl;
00306             numIsolations++;
00307             const NodeHandle handle = GlobalNodeListAccess().get()->getBootstrapNode();
00308             gateway.address = I3IPAddress(handle.getAddress(), par("serverPort"));
00309         }
00310     }
00311 
00312     /* ping gateway */
00313     insertTrigger(gatewayId, false);
00314 //    cout << "Client " << nodeIPAddress << " pings " << gatewayId << endl;
00315 
00316     /* reinsert stored triggers */
00317     set<I3Trigger>::iterator it;
00318     for (it = insertedTriggers.begin(); it != insertedTriggers.end(); it++) {
00319         insertTrigger(*it, false);
00320     }
00321 
00322     /* now that we are refreshing stuff, might as well erase old identifier cache entries */
00323     int idStoreTime = par("idStoreTime");
00324     for (mit = identifierCache.begin(); mit != identifierCache.end(); mit++) {
00325         if (mit->second.lastReply - simTime() > idStoreTime) {
00326             identifierCache.erase(mit);
00327         }
00328     }
00329 
00330 }
00331 
00332 void I3BaseApp::refreshSamples() {
00333     map<I3Identifier, I3CachedServer>::iterator mit;
00334 
00335     EV << "I3BaseApp::refreshSamples()]\n"
00336        << "    Refresh samples!"
00337        << endl;
00338     /* reinsert sample triggers */
00339     for (mit = samplingCache.begin(); mit != samplingCache.end(); mit++) {
00340         insertTrigger(mit->first, false);
00341     }
00342 }
00343 
00344 I3Identifier I3BaseApp::retrieveClosestIdentifier()
00345 {
00346     simtime_t time;
00347     I3Identifier id;
00348     map<I3Identifier, I3CachedServer>::iterator mit;
00349     I3IPAddress myAddress(nodeIPAddress, par("clientPort"));
00350 
00351     time = MAXTIME;
00352     for (mit = samplingCache.begin(); mit != samplingCache.end(); mit++) {
00353         if (time > mit->second.roundTripTime) {
00354             time = mit->second.roundTripTime;
00355             id = mit->first;
00356         }
00357     }
00358     samplingCache.erase(id);
00359 
00360     I3Identifier rid;
00361     rid.createRandomKey();
00362 
00363     ostringstream os;
00364     os << myAddress << " sample";
00365     rid.setName(os.str());
00366 
00367     samplingCache[rid] = I3CachedServer(); // placeholder
00368     insertTrigger(rid, false);
00369 
00370     return id;
00371 }
00372 
00373 void I3BaseApp::sendPacket(const I3Identifier &id, cPacket *msg, bool useHint)
00374 {
00375     I3IdentifierStack stack;
00376 
00377     stack.push(id);
00378     sendPacket(stack, msg, useHint);
00379 }
00380 
00381 void I3BaseApp::sendPacket(const I3IdentifierStack &stack, cPacket *msg, bool useHint)
00382 {
00383     I3SendPacketMessage *smsg;
00384 
00385     smsg = new I3SendPacketMessage();
00386     smsg->setBitLength(SEND_PACKET_L(smsg));
00387     smsg->encapsulate(msg);
00388     smsg->setIdentifierStack(stack);
00389 
00390     smsg->setSendReply(useHint);
00391     if (useHint) {
00392         I3IPAddress add(nodeIPAddress, par("clientPort"));
00393         smsg->setSource(add);
00394     }
00395 
00396     numSent++;
00397     sentBytes += smsg->getByteLength();
00398 
00399     I3SubIdentifier subid = stack.peek(); // first check where the packet should go
00400     if (subid.getType() == I3SubIdentifier::IPAddress) { // if it's an IP address
00401         smsg->getIdentifierStack().pop(); // pop it
00402         sendThroughUDP(smsg, subid.getIPAddress()); // and send directly to host
00403     } else { // else if it's an identifier
00404         // check if we have the I3 server cached
00405         I3IPAddress address = (useHint && identifierCache.count(subid.getIdentifier()) != 0) ?
00406                               identifierCache[subid.getIdentifier()].address :
00407                               gateway.address;
00408         sendThroughUDP(smsg, address); // send it directly
00409     }
00410 }
00411 
00412 void I3BaseApp::insertTrigger(const I3Identifier &identifier, bool store)
00413 {
00414     I3Trigger trigger;
00415     I3IPAddress add(nodeIPAddress, par("clientPort"));;
00416 
00417     trigger.getIdentifierStack().push(add);
00418     trigger.setIdentifier(identifier);
00419     insertTrigger(trigger, store);
00420 }
00421 
00422 void I3BaseApp::insertTrigger(const I3Identifier &identifier, const I3IdentifierStack &stack, bool store)
00423 {
00424     I3Trigger trigger;
00425 
00426     trigger.setIdentifier(identifier);
00427     trigger.getIdentifierStack() = stack;
00428     insertTrigger(trigger, store);
00429 }
00430 
00431 void I3BaseApp::insertTrigger(const I3Trigger &t, bool store) {
00432 
00433     if (store) {
00434         if (insertedTriggers.count(t) != 0) return;
00435         insertedTriggers.insert(t);
00436     }
00437 
00438     I3InsertTriggerMessage *msg = new I3InsertTriggerMessage();
00439     I3IPAddress myAddress(nodeIPAddress, par("clientPort"));
00440 
00441     msg->setTrigger(t);
00442     msg->setSendReply(true);
00443     msg->setSource(myAddress);
00444     msg->setBitLength(INSERT_TRIGGER_L(msg));
00445 
00446     sendThroughUDP(msg, gateway.address);
00447 }
00448 
00449 void I3BaseApp::removeTrigger(const I3Identifier &identifier)
00450 {
00451     I3Trigger dummy;
00452     dummy.setIdentifier(identifier);
00453 
00454     set<I3Trigger>::iterator it = insertedTriggers.lower_bound(dummy);
00455     if (it == insertedTriggers.end()) return; /* no matches */
00456 
00457     for (; it != insertedTriggers.end() && it->getIdentifier() == identifier; it++) {
00458         removeTrigger(*it);
00459     }
00460 }
00461 
00462 void I3BaseApp::removeTrigger(const I3Trigger &t)
00463 {
00464     I3RemoveTriggerMessage *msg = new I3RemoveTriggerMessage();
00465     msg->setTrigger(t);
00466     msg->setBitLength(REMOVE_TRIGGER_L(msg));
00467     sendThroughUDP(msg, gateway.address);
00468 
00469     insertedTriggers.erase(t);
00470 }
00471 
00472 set<I3Trigger> &I3BaseApp::getInsertedTriggers()
00473 {
00474     return insertedTriggers;
00475 }
00476 
00477 void I3BaseApp::receiveChangeNotification (int category, const cPolymorphic *details)
00478 {
00479     Enter_Method_Silent();
00480 
00481     /* Mobility is happening (the only event we are subscribed to). We have two things to do:
00482     * 1) Insert triggers with new IP
00483     * 2) Delete triggers with old IP
00484     * If it's one staged mobility, we just get told the IP after it's changed, and we need to make sure
00485     * step 1 and 2 are done. If it's two staged mobility, we need to make sure we do step 1 first and then
00486     * step 2. */
00487 
00488 //     if (!mobilityInStages) { /* if the flag isn't set, mobility isn't done in stages or this is stage 1 */
00489 //         if (category == NF_HOSTPOSITION_BEFOREUPDATE) {
00490 //             mobilityInStages = true; /* set the flag so we don't land here in stage 2 again */
00491 //         }
00492 //         /* do part 1! */
00493 //         cMessage *msg = check_and_cast<cMessage*>(details);
00494 //         IPvXAddress *ipAddr = (IPvXAddress*)msg->getContextPointer();
00495 //
00496 //         ostringstream os;
00497 //         os << "Mobility first stage - actual IP is " << nodeIPAddress << ", future IP is " << *ipAddr << endl;
00498 //         getParentModule()->bubble(os.str().c_str());
00499 //
00500 //         std::cout << "In advance from " << nodeIPAddress << " to " << *ipAddr << endl;
00501 //         I3IPAddress oldAddress(nodeIPAddress, par("clientPort"));
00502 //         I3IPAddress newAddress(*ipAddr, par("clientPort"));
00503 //
00504 //         delete ipAddr;
00505 //         delete msg;
00506 //
00507 //         for (set<I3Trigger>::iterator it = insertedTriggers.begin(); it != insertedTriggers.end(); it++) {
00508 //             I3Trigger trigger(*it); /* create copy */
00509 //             trigger.getIdentifierStack().replaceAddress(oldAddress, newAddress); /* replace old address with new */
00510 //             insertTrigger(trigger, false); /* insert trigger in I3, but don't store it in our list yet - that's done in part 2 */
00511 //         }
00512 //
00513 //         doMobilityEvent(I3_MOBILITY_BEFORE_UPDATE);
00514 //     }
00515 //     if (category == NF_HOSTPOSITION_UPDATED) { /* part 2: both for 1-stage and stage 2 of 2-stage mobility */
00516 //         I3IPAddress oldAddress(nodeIPAddress, par("clientPort"));
00517 //         nodeIPAddress = IPAddressResolver().addressOf(getParentModule()).get4();
00518 //         I3IPAddress newAddress(nodeIPAddress, par("clientPort"));
00519 //
00520 //         cout << "After from " << oldAddress << " to " << newAddress << endl;
00521 //
00522 //         ostringstream os;
00523 //         os << "Mobility second stage - setting IP as " << newAddress << endl;
00524 //         getParentModule()->bubble(os.str().c_str());
00525 //
00526 //         set<I3Trigger> newSet; /* list of new triggers (that we already inserted in I3 in stage 1) */
00527 //
00528 //         for (set<I3Trigger>::iterator it = insertedTriggers.begin(); it != insertedTriggers.end(); it++) {
00529 //             I3Trigger trigger(*it); /* create copy */
00530 //
00531 //             trigger.getIdentifierStack().replaceAddress(oldAddress, newAddress); /* replace old address with new */
00532 //             newSet.insert(trigger); /* insert in new list */
00533 //
00534 //             removeTrigger(*it);  /* remove trigger from I3 and out list */
00535 //
00536 //         }
00537 //         insertedTriggers = newSet; /* replace old list with updated one */
00538 //
00539 //         mobilityInStages = false; /* reset variable */
00540 //         refreshTriggers(); /* to get new trigger round-trip times, new cache list */
00541 //      refreshSamples();
00542 //
00543 //         doMobilityEvent(I3_MOBILITY_UPDATED);
00544 //     }
00545 }
00546 
00547 void I3BaseApp::doMobilityEvent(I3MobilityStage category)
00548 {
00549 }
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3