/* * File: Moversight.cc * Author: jgaebler * * Created on September 20, 2010, 1:30 PM */ #include "Moversight.h" #include "Dispatcher.h" #include "common/transport/MoversightMessageTypes.h" #include "common/transport/TransportAddress.h" #include "common/transport/msg/ExteriorMessage.h" #include "common/validator/MessageValidator.h" #include "ms/Peer.h" #include "ms/msg/MSMessageFactory.h" #include "mt/timer/MTTimer.h" #include "mt/msg/MulticastMessage.h" #include "fd/NetworkFailureDetectorType.h" #if OMNETPP #include "app/Application.h" #include "app/ApplicationLevelMulticastTestApplication.h" #include "app/MergeApplication.h" #include "app/PeerplacingApplication.h" #include "app/SplitApplication.h" #include "app/TestApplication.h" #include "app/PartitionApplication.h" #include "app/PendingTestApplication.h" #include "app/MaintanceApplication.h" //omnet address related stuff #include "IPvXAddressResolver.h" #include "UDPControlInfo.h" #include "InterfaceEntry.h" #include "IInterfaceTable.h" #include "IPvXAddress.h" #include "IPv4InterfaceData.h" #include "mobility/models/MovingMobilityBase.h" #include "mobility/models/StationaryMobility.h" #endif namespace ubeeme { namespace moversight { #if OMNETPP #define simulationTriggerTimeout 10 /** * @brief Declares Moversight as omnetpp module. */ Define_Module(Moversight); #else Moversight::Moversight(MoversightCallback & callBack) : UDPNodeEventReceiver(0, false), infoObject(NULL), dispatcher(*this, callBack) { #if 0 bool printDebugDIS; bool printDebugNFD; bool printDebugMT; bool printDebugMS; bool printDebugTC; bool printDebugST; bool printDebugCT; bool printDebugAPP; bool enableNFD; bool enableMobilitySupport = default(true); bool enableNetworkFailureDetector = default(true); bool enableStreamTransfer = default(true); #endif setNFDEnabled(false); initialize(0); } Moversight::~Moversight() { }//End #endif /** * @brief Returns the local address. * @return The local address. */ TransportAddress & Moversight::getLocalAddress() { #if UBEEME bool success = false; if (infoObject.isNull()) { success = initNetworkInfos(); } if (success) { PhysicalNetworkInterface::AddressEntryList addressList = infoObject->addressList; PhysicalNetworkInterface::AddressEntryList::iterator it = addressList.begin(); if (it != addressList.end()) { if (it->ip().protocol() == QAbstractSocket::IPv4Protocol) { MOV_DEBUG << "Local: " << it->ip().toString(); localTA = TransportAddress(it->ip(), infoObject->boundPort); } }//End if } else { localTA = TransportAddress(); } #endif return localTA; } #if OMNETPP /** * @brief Sets the local transport address of the current host */ void Moversight::setLocalAddress() { cModule *mod = getParentModule(); // get the MoversightPeer IInterfaceTable* ift = IPvXAddressResolver().findInterfaceTableOf(mod); //set the local address if (ift && ift->getNumInterfaces() > 1) { //interface index 0 == loopback InterfaceEntry *ie = ift->getInterface(1); localTA = TransportAddress(ie->ipv4Data()->getIPAddress()); } else { localTA = TransportAddress(); } //set the port localTA.setPort(int(par("localPort"))); } #endif /** * @brief Initialize the Moversight instance */ void Moversight::initialize(int stage) { #if OMNETPP if (stage != 3) return; setLocalAddress(); app = NULL; visu = NULL; dispatcher = NULL; simulationTrigger = NULL; //set Socket socket.setOutputGate(gate("udpOut")); socket.bind(localTA.getPort()); //read the simulation parameter and setup the module peerPlacingStrategyType = PeerPlacingStrategyType(int (par("peerPlacingStrategy"))); peerPlacingStrategyMetricType = PeerPlacingStrategyMetricType(int (par("peerPlacingStrategyMetric"))); maintanceMomentMetricType = MaintanceMomentMetricType((int) (par("maintanceMomentMetricType"))); failureDetectorType = NetworkFailureDetectorType(int (par("failureDetectorType"))); peerResourcesValue = PeerResources(PeerResources::ResourceValue(par("peerResourceValue"))); //read max cluster maxClusterCount = int(par("maxClusterCount")); maxPeerCount = int(par("maxPeerCount")); // // wireless Nodes register in category we want to listen with // if (getParentModule()->getSubmodule("wlan", 0)) { // notificationBoard = dynamic_cast (getParentModule()->getSubmodule("notificationBoard")); // if (!notificationBoard) // std::cerr << "Could not find NotificationBoard module with name 'notificationBoard' " << getParentModule() << endl; // else { // //categories we are interested in // notificationBoard->subscribe(this, NF_L2_ASSOCIATED_NEWAP); // notificationBoard->subscribe(this, NF_L2_BEACON_LOST); // } // } app = NULL; //load the proper test app switch (int(par("testApp"))) { case SPLIT_TEST_APPLICATION: app = new SplitApplication(*this); break; case NFD_TEST_APPLICATION: throw ParameterException("initialize - set up NFD_TEST_APPLICATION not implemented yet"); break; case PEER_PLACING_TEST_APPLICATION: app = new PeerplacingApplication(*this); break; case TEST_APPLICATION: app = new TestApplication(*this); break; case MERGE_TEST_APPLICATION: app = new MergeApplication(*this); break; case ALM_TEST_APPLICATION: app = new ApplicationLevelMulticastTestApplication(*this); break; case PARTITION_APPLICATION: app = new PartitionApplication(*this); break; case PENDING_TEST_APPLICATION: app = new PendingTestApplication(*this); break; case MAINTANCE_APPLICATION: app = new MaintanceApplication(*this); break; default: throw ParameterException("initialize - no valid value for parameter \"application\" specified"); break; }//end switch enableRecordStats = par("recordStat").boolValue(); if(enableRecordStats){ numMessagesReceived = 0; numMessagesSent = 0;; }//end if setNFDEnabled(par("enableNFD").boolValue()); //initialize print debug parameter setPrintDebugAPP(par("printDebugAPP").boolValue()); setPrintDebugDIS(par("printDebugDIS").boolValue()); setPrintDebugNFD(par("printDebugNFD").boolValue()); setPrintDebugMT(par("printDebugMT").boolValue()); setPrintDebugMS(par("printDebugMS").boolValue()); setPrintDebugTC(par("printDebugTC").boolValue()); setPrintDebugST(par("printDebugST").boolValue()); setPrintDebugCT(par("printDebugCT").boolValue()); setPrintDebugUT(par("printDebugUT").boolValue()); setPrintDebugMOB(par("printDebugMOB").boolValue()); setPrintDebugVISU(par("printDebugVISU").boolValue()); setPrintDebugES(par("printDebugES").boolValue()); setPrintDebugUC(par("printDebugUC").boolValue()); setPrintDebugAC(par("printDebugAC").boolValue()); //start moversight dispatcher = new Dispatcher(*this, *app); //initialize the test application app->setDispatcher(dispatcher); app->initialise(); dispatcher->initialise(); simulationTrigger = new cMessage("simulationTrigger"); if (par("simulationTrigger").boolValue()) { scheduleAt(simTime() + simulationTriggerTimeout, simulationTrigger); }//End if //start the visualization visu = new MoversightSimulationPeerStateVisualization(*dispatcher); visu->initialise(); updateSimUI(); #else stage = stage; //set up the peerplacing stuff peerPlacingStrategyType = BALANCED_PEER_PLACING; peerPlacingStrategyMetricType = OUCMETRIC_CLUSTERSIZE; maintanceMomentMetricType = RESOURCEVALUEMOMENTMETRIC; failureDetectorType = BERTIER_DETECTOR; maxClusterCount = 12; maxPeerCount = 6; // setLocalAddress(); dispatcher.initialise(); #endif }//End initialize /** * @brief Finish method. Is called during shutdown of moversight. */ void Moversight::finish() { #if OMNETPP if(enableRecordStats){ recordScalar("messages_sent:count", numMessagesSent); recordScalar("messages_received:count", numMessagesReceived); }//End if if (app != NULL) { app->finalise(); delete app; app = NULL; }//End if if (visu != NULL) { delete visu; visu = NULL; }//End if if (dispatcher != NULL) { delete dispatcher; dispatcher = NULL; }//End if if (simulationTrigger != NULL) { cancelAndDelete(simulationTrigger); simulationTrigger = NULL; }//end if #endif } #if OMNETPP /** * @brief Handles received messages (from the socket) and timers. * @param msg The received message to handle. */ void Moversight::handleMessage(cMessage *msg) { // timer handling if (msg->isSelfMessage()) { cancelEvent(msg); if (msg == simulationTrigger) { handleSimulationTriggerTimer(); }//End if else if (dynamic_cast (msg)) { MoversightTimer* timer = dynamic_cast (msg); timer->fire(); dispatcher->getEventService().process(); }//End else if }//End if // not a timer else { if(enableRecordStats) numMessagesReceived++; MoversightMessage * mMsg = dynamic_cast (msg); if (mMsg != NULL) { GenericTime arrivalTime = GenericTime::currentTime(); mMsg->setArrivalTime(arrivalTime); dispatcher->handleMessage(mMsg); delete msg; msg = NULL; } else { MOV_DEBUG << "ERROR: handleMessage - unknown message type - drop message"; } }//End else } /** * @brief test code method */ void Moversight::handleSimulationTriggerTimer() { if (app != NULL) { app->startTestCase(int(par("testCase"))); } } /** * @brief This method updates the presentation of a peer within the omnett++ visualization. In particular, the * icon of the peer is change depending on the role of the peer (master or slave). */ void Moversight::updateSimUI() { if (visu != NULL) { visu->updateSimUI(); } } /** * @brief Displays a message bubble at the omnet sim ui. * @param msg */ void Moversight::bubble(const char* msg) { getParentModule()->bubble(msg); } /** * @brief Schedules the simulation trigger timer. * @param time The duration to the determined schedule. */ void Moversight::scheduleTestCase(simtime_t time) { cancelEvent(simulationTrigger); scheduleAt((simTime() + time), simulationTrigger); } /** * @brief receive notifications from notificationBoard * @param category to identifiy the matter of changed Notification */ void Moversight::receiveChangeNotification(int category, const cPolymorphic *details) { switch (category) { case NF_L2_ASSOCIATED_NEWAP: std::cerr << dispatcher->getLocalPeer().getPeerID() << " Connection to an AP established " << endl; //connectionEstablished(); break; case NF_L2_BEACON_LOST: std::cerr << dispatcher->getLocalPeer().getPeerID() << " Connection to an AP lost" << endl; // dispatcher.signalConnectionLost(); break; } } #endif /** * @brief Returns the user selected peer placing strategy type. * @see PeerPlacingStrategy.h * @return The selected strategy type. */ const PeerPlacingStrategyType & Moversight::getPeerPlacingStrategyType() const { return peerPlacingStrategyType; } const PeerPlacingStrategyMetricType & Moversight::getPeerPlacingStrategyMetricType() const { return peerPlacingStrategyMetricType; } const MaintanceMomentMetricType & Moversight::getMaintanceMomentMetricType() const { return maintanceMomentMetricType; } const PeerResources & Moversight::getPeerResources() const { return peerResourcesValue; } /** * @brief Returns the user selected failure detector type. * @see FailureDetectorType.h * @return The selected failure detector type. */ const NetworkFailureDetectorType & Moversight::getFailureDetectorType() const { return failureDetectorType; } /** * @brief Returns the maximal number of clusters * @return number of clusters */ size_t Moversight::getMaxClusterCount() { return maxClusterCount; } /** * @brief Returns the maximal number of peers in one cluster * @return number of peers */ size_t Moversight::getMaxPeerCount() { return maxPeerCount; } /** * @brief Sends a omnet message to a peer, identified by its transport address * @param msg The message to send * @param toPeerTA The destination address */ void Moversight::sendToPeer( const MoversightMessage& msg, const TransportAddress & toPeerTA) { #if OMNETPP if(enableRecordStats) numMessagesSent++; sendToUDP(msg, toPeerTA); } #else void Moversight::sendToPeer(MoversightMessage & msg, const TransportAddress & toPeerTA) { delegateSend(msg, toPeerTA); } #endif #if OMNETPP /** * @brief Sending the Message via UDP to the given TransportAddress * @param packet The Message to send * @param destAddr The destination transport address of the message */ void Moversight::sendToUDP( const MoversightMessage& packet, const TransportAddress& destAddr) { cPacket* msg = (cPacket *) packet.dup(); //without -> no local deletion of send message // send message to UDP, with the appropriate control info attached msg->setKind(UDP_C_DATA); msg->setByteLength(sizeof packet); socket.sendTo(msg, destAddr.getHostAddress(), destAddr.getPort()); } #endif /** * @brief Assignment operator. * @param other The instance to assign. * @return A reference of the current object. */ Moversight & Moversight::operator =(Moversight const & other) { if (this == &other) { return *this; } BaseMoversight::operator=(other); dispatcher = other.dispatcher; #if OMNETPP simulationTrigger = other.simulationTrigger; app = other.app; numMessagesReceived = other.numMessagesReceived; numMessagesSent = other.numMessagesSent; maxClusterCount = other.maxClusterCount; maxPeerCount = other.maxPeerCount; enableRecordStats = other.enableRecordStats; socket = other.socket; #endif peerPlacingStrategyType = other.peerPlacingStrategyType; peerPlacingStrategyMetricType = other.peerPlacingStrategyMetricType; maintanceMomentMetricType = other.maintanceMomentMetricType; failureDetectorType = other.failureDetectorType; return *this; }//End #if UBEEME /** * @brief Delegates the data to the receiver * @param buffer ByteArray of data * @param from PeerID from the sender */ void Moversight::delegateReceive(ByteArray const &buffer, PeerID const &from) { DatagramInput::delegateReceive(buffer, from); } /** * @brief Chains the given DatagramInput to this DatagramOutput. So it can be used for delegating. * @param input Input to chain. */ void Moversight::chainDown(DatagramInput *input) { DatagramOutput::chainDown(input); if (!initNetworkInfos()) { MOV_DEBUG << "Cannot init network informations."; } dispatcher.initialise(); } /** * @brief Unchains the given input from this DatagramOutput. * @param input Input to unchain. */ void Moversight::unchainDown(DatagramInput *input) { DatagramOutput::unchainDown(input); infoObject.clear(); disconnectReceiver(); } bool Moversight::initNetworkInfos() { DatagramInput *input = 0; if (!inputList.empty()) { input = inputList.front(); } if (input && infoObject.isNull()) { typedef std::list > UDPInfoObjectList; UDPInfoObjectList objectList; UDPInfoObjectList::iterator it; UDPEndpoint *currentUDPEndpoint = 0; InformationBroker::getInstance()->getInformationObjectList(objectList); for (it = objectList.begin(); it != objectList.end(); ++it) { currentUDPEndpoint = (*it)->getOwner(); if (input == currentUDPEndpoint || input->hasInputNodeInChain(currentUDPEndpoint)) { infoObject = *it; connectReceiver(currentUDPEndpoint); connectAll(); return true; } } } return false; } /** * @brief * @param e The EventContainer */ void Moversight::stateChanged(EventContainer e) { UDPStateChangedEvent *changed = e.decapsulate (); if (changed) { if (changed->getUDPState() == ubeeme::UDPEndpoint::UNCONNECTED_STATE) { MOV_DEBUG << "UDP unconnected, delete information object."; infoObject.clear(); disconnectReceiver(); initNetworkInfos(); } dispatcher.initialise(); } } /** * @brief Method checks whether the given DatagramInput is situated under the chain. * Therefor bool NetworkOutput::hasNodeInChain(NETWORK_INPUT const *input) const is called. * In case it's a DatagramOutput * * @param input searched DatagramInput * @return if the DatagramInput searched for is below us */ bool Moversight::hasInputNodeInChain(DatagramInput const * /*input*/) const { return false; }//End /** * @brief This is the callback, that gets called when the down linked node received data and forwards those to us. * @param buffer all the received data * @param from - sender of the data * @param fromInput - reference to the linked node, from whom we got the data (can be ignored in most cases) */ void Moversight::handleReceive(ByteArray const &buffer, TransportAddress const &from, DatagramInput const * /*fromInput*/) { SharedPointer received = factory.NetworkMessageFactory::createMessage(buffer, from); if (!received.isNull()) { dispatcher.handleMessage((MoversightMessage *) received.data()); } } /** * @brief this is the callback, that gets called when the up linked node wants to send data to us * @param buffer - the data to be send * @param to - the receiver of the data * @param fromOutput - reference to the linked node that wants to send the data to us (can be ignored in most cases) * @return - true on successfull sending, otherwise false. */ bool Moversight::handleSend(ByteArray const &buffer, PeerID const &/*to = 0*/, DatagramOutput const * /*fromOutput = 0 */) { GroupData data; //("DT"); data.setData(buffer); dispatcher.sendMessage(data); return true; } /** * @brief Invite a peer to the group * @param destTa The transportAddress of the peer to invite * @param pDesc the peerDescription */ void Moversight::invitePeer(TransportAddress & destTa, PeerDescription & pDesc) { dispatcher.invitePeer(destTa, pDesc); }//End /** * @brief Cancel the invitation * @param ta The transportAddress to send the cancellation * @param reason Why the invitation is turned down */ void Moversight::cancelInvitation(TransportAddress & ta, std::string reason) { dispatcher.cancelInvitation(ta, reason); } /** * @brief Accept the Invitation * @param inv The invitation to accept * @param comment A comment * @param pDesc PeerDescription */ void Moversight::acceptInvitation(Invitation & inv, std::string comment, PeerDescription & pDesc) { dispatcher.acceptInvitation(inv, comment, pDesc); }//End /** * @brief Reject the invitation * @param inv The invitation to be rejected * @param reason Why it's rejected */ void Moversight::rejectInvitation(Invitation & inv, std::string reason) { dispatcher.rejectInvitation(inv, reason); } /** * @brief Leave the group */ void Moversight::leaveGroup() { dispatcher.leaveGroup(); }//End /** * @brief Start a split * @param options The split options * @param size The number of the splitting peers * @param splitPeers PeerIDList of the splitting peers */ void Moversight::splitGroup(unsigned char options, PeerIDList splitPeers) { dispatcher.splitGroup(options, splitPeers); } /** * @brief Start a group Merge * @param destTa The other Mergedirector */ void Moversight::mergeGroup(TransportAddress & destTa) { dispatcher.mergeGroup(destTa); }//End /** * @brief Accept the merge request */ void Moversight::acceptGroupMerge() { dispatcher.acceptGroupMerge(); } /** * @brief Reject the merge request * @param reason Why it's rejected */ void Moversight::rejectGroupMerge(std::string & reason) { dispatcher.rejectGroupMerge(reason); } #endif } }