595 lines
15 KiB
C++
595 lines
15 KiB
C++
/*
|
|
* File: MaintanceApplication.cc
|
|
* Author: stubbfel
|
|
*
|
|
* Created on June 29, 2013
|
|
*/
|
|
#include "MaintanceApplication.h"
|
|
|
|
#include "Dispatcher.h"
|
|
#include "Moversight.h"
|
|
#include "ms/Invitation.h"
|
|
#include "common/transport/TransportAddress.h"
|
|
#include "simutils/OmnetppIniUtils.h"
|
|
#include "mt/msg/GroupData.h"
|
|
#include <fstream>
|
|
|
|
#include "ms/events/GroupClosedEvent.h"
|
|
#include "ms/events/JoinRequestEvent.h"
|
|
#include "ms/events/LocalPeerUpdatedEvent.h"
|
|
#include "ms/events/PeerJoinedEvent.h"
|
|
#include "ms/events/PeerLeftEvent.h"
|
|
#include "mt/events/MulticastMessageDroppedEvent.h"
|
|
|
|
#undef DEBUG
|
|
#define DEBUG(msg) if (module.isPrintDebugAPP()) \
|
|
MOV_DEBUG << "APP@"<<(dis->getLocalState()==DISJOINED?"TA_":"");\
|
|
if(dis->getLocalState()==DISJOINED){MOV_DEBUG << module.getLocalAddress();}\
|
|
else{MOV_DEBUG<< dis->getMembershipService().getLocalID();}MOV_DEBUG<<" "<<msg<<std::endl;
|
|
|
|
namespace ubeeme {
|
|
namespace moversight {
|
|
|
|
const unsigned int MaintanceApplication::INITIAL_FAKEID;
|
|
const unsigned int MaintanceApplication::MS_TO_INT_FACTOR;
|
|
|
|
/**
|
|
* @brief Constructor
|
|
* @param m A reference to the moversight instance
|
|
*/
|
|
MaintanceApplication::MaintanceApplication(Moversight & m) : Application(m, "MaintanceApplication"), RTTStat(m, "RTT") { /*, groupSizeStat(m, "groupSize"), groupSize(0) */
|
|
inGroup = false;
|
|
stopTest = false;
|
|
emptyCommandList = false;
|
|
nextCommand = true;
|
|
}
|
|
|
|
/**
|
|
* @brief Destructor
|
|
*/
|
|
MaintanceApplication::~MaintanceApplication() {
|
|
}
|
|
|
|
void
|
|
MaintanceApplication::initialise() {
|
|
dis->subscribe<GroupClosedEvent>(this);
|
|
dis->subscribe<PeerJoinedEvent>(this);
|
|
dis->subscribe<PeerLeftEvent>(this);
|
|
dis->subscribe<LocalPeerUpdatedEvent>(this);
|
|
dis->subscribe<JoinRequestEvent>(this);
|
|
dis->subscribe<MulticastMessageDroppedEvent>(this);
|
|
}
|
|
|
|
void
|
|
MaintanceApplication::finalise() {
|
|
dis->unsubscribeAll(this);
|
|
}
|
|
|
|
/**
|
|
* @brief Starts the given test case.
|
|
* @param i The number of the test case to start.
|
|
*/
|
|
void
|
|
MaintanceApplication::startTestCase(unsigned int i) {
|
|
if (stopTest) {
|
|
return;
|
|
}
|
|
|
|
switch (i) {
|
|
case 0:
|
|
testCase00();
|
|
break;
|
|
|
|
case 1:
|
|
testCase01();
|
|
break;
|
|
|
|
case 2:
|
|
testCase02();
|
|
break;
|
|
|
|
case 3:
|
|
testCase03();
|
|
break;
|
|
|
|
case 4:
|
|
testCase04();
|
|
break;
|
|
|
|
case 5:
|
|
testCase05();
|
|
break;
|
|
|
|
case 6:
|
|
testCase06();
|
|
break;
|
|
|
|
default:
|
|
throw NotImplementedYetException("not implemented");
|
|
break;
|
|
}
|
|
}//End startTestCase
|
|
|
|
/**
|
|
*@brief simple test run with random leaves and joins
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase00() {
|
|
joinRate = 1;
|
|
leaveRate = 1;
|
|
defaultBehav();
|
|
}//End testCase00
|
|
|
|
/**
|
|
*@brief simple test run coordinatet leaves and joins
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase01() {
|
|
joinRate = 1; // == 100%
|
|
leaveRate = 2; // == 50%
|
|
commandsFileName = "commands/comt01.txt";
|
|
coordinateBehav();
|
|
module.scheduleTestCase(1);
|
|
}//End testCase01
|
|
|
|
/**
|
|
*@brief testrun for simultaneously invataitons
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase02() {
|
|
joinRate = 1; // == 100%
|
|
leaveRate = 1; // == 0%
|
|
defaultBehav2();
|
|
}//End testCase02
|
|
|
|
/**
|
|
*@brief coordiante testrun, if all commands are executed then moduel==1 start to send groupdatas
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase03() {
|
|
commandsFileName = "commands/com.txt";
|
|
coordinateBehav();
|
|
|
|
if (moduleIndex == 1 && dis->getLocalState() == JOINED) {
|
|
// abuse sendMessage for transmitting first sending time of the messages
|
|
sendKickMessage(createFakeID(GenericTime::currentTime().dbl() * MS_TO_INT_FACTOR));
|
|
}//End if
|
|
|
|
module.scheduleTestCase(1);
|
|
}
|
|
|
|
/**
|
|
*@brief test run, for testing random forces role switch (module== ire sending RSA Messages)
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase04() {
|
|
commandsFileName = "commands/comt04.txt";
|
|
module.scheduleTestCase(45);
|
|
coordinateBehav();
|
|
|
|
if (dis->getLocalState() == JOINED &&
|
|
commands.size() < 1 &&
|
|
moduleIndex == 1 &&
|
|
dis->getLocalSubState() != FLUSHING) {
|
|
PeerIDList masterIdList = dis->getMembershipService().getMasterPeerIDList();
|
|
PeerID switchMasterId = masterIdList.get(rand() % masterIdList.size());
|
|
dis->getMaintenanceRoleService().sendRSAMessage(switchMasterId);
|
|
}
|
|
|
|
module.scheduleTestCase(1);
|
|
}
|
|
|
|
/**
|
|
*@brief uncoordiante testrun, moduel==1 send groupdatas
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase05() {
|
|
joinRate = 5;
|
|
leaveRate = 100;
|
|
defaultBehav();
|
|
|
|
if (moduleIndex == 1 && dis->getLocalState() == JOINED) {
|
|
// abuse sendMessage for sending "useless" messages
|
|
sendKickMessage(createFakeID(0));
|
|
}//End if
|
|
|
|
module.scheduleTestCase(1);
|
|
}
|
|
|
|
/**
|
|
*@brief coordiante testrun, if all commands are executed then moduel==1 start to send groupdatas (like testcase 3 but sending messages as a burst)
|
|
*/
|
|
void
|
|
MaintanceApplication::testCase06() {
|
|
commandsFileName = "commands/comt03.txt";
|
|
//module.scheduleTestCase(45);
|
|
coordinateBehav();
|
|
|
|
if (moduleIndex == 1 && dis->getLocalState() == JOINED && emptyCommandList) {
|
|
// send a the current time as fakeID
|
|
sendKickMessage(createFakeID(GenericTime::currentTime().dbl() * MS_TO_INT_FACTOR));
|
|
module.scheduleTestCase(0.001);
|
|
} else {
|
|
module.scheduleTestCase(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief excute the normal behaviour of the app, depends of the join- and
|
|
* leaverate, the module==1 will be insert peers. every Peer decided self,
|
|
* when they want to leave the group (Except module==1||2 )
|
|
*/
|
|
void
|
|
MaintanceApplication::defaultBehav() {
|
|
moduleIndex = module.getLocalAddress().getHostAddress().get4().getDByte(3);
|
|
|
|
if (initApp) {
|
|
candidates = OmnetppIniUtils::getDestinationAddressesFromOmnetppIni(module);
|
|
initApp = false;
|
|
}//End if
|
|
|
|
//------------------------------------------------------------------
|
|
//run the app
|
|
//------------------------------------------------------------------
|
|
if (moduleIndex == 1) { // starts counting at 1
|
|
//we have more candidates?
|
|
if (candidates.size() > 0) {
|
|
int join = rand() % joinRate;
|
|
|
|
if (join == 0) {
|
|
TransportAddress first = candidates.first();
|
|
candidates.remove(first);
|
|
invitePeer(first);
|
|
}
|
|
}
|
|
|
|
//module.scheduleTestCase(45);
|
|
} else {
|
|
if (dis->getLocalState() == JOINED) {
|
|
inGroup = true;
|
|
} else {
|
|
inGroup = false;
|
|
}
|
|
|
|
if (inGroup && dis->getGroupSize() > 2) {
|
|
int leave = rand() % leaveRate;
|
|
|
|
if (leave == 1) {
|
|
leaveGroup();
|
|
}
|
|
|
|
//module.scheduleTestCase(45);
|
|
}
|
|
}//End if
|
|
|
|
module.scheduleTestCase(45);
|
|
}
|
|
|
|
/**
|
|
* @brief excute the normal behaviour of the app, depends of the join- and
|
|
* leaverate, the module==1||2 will be insert peers. every Peer decided self,
|
|
* when they want to leave the group (Except module==1||2 )
|
|
*/
|
|
void
|
|
MaintanceApplication::defaultBehav2() {
|
|
moduleIndex = module.getLocalAddress().getHostAddress().get4().getDByte(3);
|
|
|
|
if (initApp) {
|
|
candidates = OmnetppIniUtils::getDestinationAddressesFromOmnetppIni(module);
|
|
initApp = false;
|
|
}//End if
|
|
|
|
//------------------------------------------------------------------
|
|
//run the app
|
|
//------------------------------------------------------------------
|
|
if (moduleIndex == 1) { // starts counting at 1
|
|
//we have more candidates?
|
|
if (candidates.size() > 0) {
|
|
int join = rand() % joinRate;
|
|
|
|
if (join == 0) {
|
|
TransportAddress first = candidates.first();
|
|
candidates.remove(first);
|
|
invitePeer(first);
|
|
}
|
|
}
|
|
|
|
//module.scheduleTestCase(45);
|
|
} else if (moduleIndex == 2) { // starts counting at 2
|
|
if (dis->getLocalState() == JOINED) {
|
|
inGroup = true;
|
|
} else {
|
|
inGroup = false;
|
|
}
|
|
|
|
//we have more candidates?
|
|
if (candidates.size() > 0 && inGroup) {
|
|
int join = rand() % joinRate;
|
|
|
|
if (join == 0) {
|
|
TransportAddress last = candidates.get(candidates.size() - 1);
|
|
candidates.remove(last);
|
|
invitePeer(last);
|
|
}
|
|
}
|
|
|
|
//module.scheduleTestCase(45);
|
|
} else {
|
|
if (dis->getLocalState() == JOINED) {
|
|
inGroup = true;
|
|
} else {
|
|
inGroup = false;
|
|
}
|
|
|
|
if (inGroup && dis->getGroupSize() > 2) {
|
|
int leave = rand() % leaveRate;
|
|
|
|
if (leave == 1) {
|
|
leaveGroup();
|
|
}
|
|
|
|
//module.scheduleTestCase(45);
|
|
}
|
|
}//End if
|
|
|
|
module.scheduleTestCase(45);
|
|
}
|
|
|
|
/**
|
|
* @brief excute the coordinated behaviour of the app, depends of the join- and
|
|
* leavecommands from a certean, the module==1 will be insert or remove peers
|
|
*/
|
|
void
|
|
MaintanceApplication::coordinateBehav() {
|
|
moduleIndex = module.getLocalAddress().getHostAddress().get4().getDByte(3);
|
|
|
|
if (initApp) {
|
|
candidates = OmnetppIniUtils::getDestinationAddressesFromOmnetppIni(module);
|
|
initApp = false;
|
|
|
|
if (moduleIndex == 1) {
|
|
std::ifstream commandFile(commandsFileName.c_str());
|
|
|
|
if (commandFile.is_open()) {
|
|
std::string command;
|
|
DEBUG("Load commands");
|
|
|
|
while (commandFile.good()) {
|
|
std::getline(commandFile, command);
|
|
DEBUG(command);
|
|
commands.add(command);
|
|
}
|
|
|
|
commandFile.close();
|
|
}
|
|
|
|
module.scheduleTestCase(45);
|
|
}//End if
|
|
}//End if
|
|
|
|
//------------------------------------------------------------------
|
|
//run the app
|
|
//------------------------------------------------------------------
|
|
if (moduleIndex == 1) { // starts counting at 1
|
|
//we have more candidates?
|
|
if (commands.size() > 0 && nextCommand == true) {
|
|
std::string command = commands.first();
|
|
commands.pop();
|
|
DEBUG("exec command " << command);
|
|
|
|
switch (command[0]) {
|
|
case 'J':
|
|
nextCommand = false;
|
|
|
|
if (candidates.size() > 0) {
|
|
TransportAddress firstAddr = candidates.first();
|
|
invitePeer(firstAddr);
|
|
candidates.pop();
|
|
}
|
|
|
|
break;
|
|
|
|
case 'L': {
|
|
nextCommand = false;
|
|
PeerID kickPeerID;
|
|
|
|
if (command.size() == 3) {
|
|
size_t firstNumber = (size_t)(command[1] - '0');
|
|
size_t secondNumber = (size_t)(command[2] - '0');
|
|
kickPeerID = firstNumber * 10 + secondNumber;
|
|
} else {
|
|
kickPeerID = (PeerID)(command[1] - '0');
|
|
}
|
|
|
|
sendKickMessage(kickPeerID);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else if (commands.size() == 0) {
|
|
emptyCommandList = true;
|
|
}
|
|
|
|
// module.scheduleTestCase(45);
|
|
}
|
|
}
|
|
|
|
void
|
|
MaintanceApplication::sendKickMessage(PeerID pId) {
|
|
DEBUG("sendData - stream dummy data to the group");
|
|
GroupData data;
|
|
data.setData(peerIDToByte(pId));
|
|
dis->sendMessage(data);
|
|
}
|
|
|
|
/**
|
|
* @brief convert a PeerID to a ByteArray
|
|
* @param id which has to been convert
|
|
*/
|
|
ByteArray
|
|
MaintanceApplication::peerIDToByte(PeerID pId) {
|
|
ByteArray array;
|
|
array.push_back(pId.getValue() & 0xff);
|
|
array.push_back(pId.getValue() >> 8 & 0xff);
|
|
array.push_back(pId.getValue() >> 16 & 0xff);
|
|
array.push_back(pId.getValue() >> 24 & 0xff);
|
|
return array;
|
|
}
|
|
|
|
/**
|
|
* @brief convert a ByteArray to a PeerId
|
|
* @param array which has to been convert
|
|
*/
|
|
PeerID
|
|
MaintanceApplication::byteToPeerID(ByteArray array) {
|
|
unsigned int intPid = 0;
|
|
char* chPID = (char*) &intPid;
|
|
*chPID = array[0];
|
|
chPID++;
|
|
*chPID = array[1];
|
|
chPID++;
|
|
*chPID = array[2];
|
|
chPID++;
|
|
*chPID = array[3];
|
|
return PeerID(intPid);
|
|
}
|
|
|
|
/**
|
|
* @brief Invites a peer to a the moversight group.
|
|
* @param ta The transport address of the peer to invite.
|
|
*/
|
|
void
|
|
MaintanceApplication::invitePeer(TransportAddress & ta) {
|
|
PeerDescription pDesc;
|
|
dis->invitePeer(ta, pDesc);
|
|
}
|
|
|
|
/**
|
|
* @brief Leaves the current group. The peer leafs the current group be
|
|
* emmiting a LeaveAnnounce within the current group.
|
|
*/
|
|
void
|
|
MaintanceApplication::leaveGroup() {
|
|
dis->leaveGroup();
|
|
}
|
|
|
|
/**
|
|
* @brief Handle an incoming JoinRequestEvent.
|
|
* @param e The event.
|
|
*/
|
|
void
|
|
MaintanceApplication::handleEvent(const JoinRequestEvent & e) {
|
|
PeerDescription desc;
|
|
PeerResources resource;
|
|
dis->acceptInvitation(e.getInvitation(), "accept invitation", desc, module.getPeerResources());
|
|
}
|
|
|
|
/**
|
|
* @brief Handle PeerJoinedEvent.
|
|
* @param e The event.
|
|
*/
|
|
void
|
|
MaintanceApplication::handleEvent(const PeerJoinedEvent & e) {
|
|
nextCommand = true;
|
|
}
|
|
|
|
/**
|
|
* @brief Handle an incoming PeerLeftEvent.
|
|
* @param e The event.
|
|
*/
|
|
void
|
|
MaintanceApplication::handleEvent(const PeerLeftEvent & e) {
|
|
|
|
if (moduleIndex == 1) {
|
|
if (!candidates.contains(e.getPeer().getLocalAddress())) {
|
|
candidates.add(e.getPeer().getLocalAddress());
|
|
}
|
|
}
|
|
|
|
nextCommand = true;
|
|
}
|
|
|
|
/**
|
|
* @brief Handle an incoming LocalPeerUpdatedEvent.
|
|
* @param e The event.
|
|
*/
|
|
void
|
|
MaintanceApplication::handleEvent(const LocalPeerUpdatedEvent & e) {
|
|
std::stringstream buf;
|
|
buf << "Peer-State - PID: " << e.getPeer().getPeerState();
|
|
DEBUG(buf.str().c_str());
|
|
}
|
|
|
|
/**
|
|
* @brief Handle an incoming GroupClosedEvent.
|
|
* @param e The event.
|
|
*/
|
|
void
|
|
MaintanceApplication::handleEvent(const GroupClosedEvent & e) {
|
|
if (moduleIndex == 1) {
|
|
stopTest = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief handler for incomming Group Data
|
|
* @param data, referennce of the new messages
|
|
* @param sender , id of the peer which sended this message
|
|
*/
|
|
void
|
|
MaintanceApplication::receiveGroupData(const GroupData & dat, const PeerID sender) {
|
|
ByteArray array = dat.getData();
|
|
PeerID pID = byteToPeerID(array);
|
|
std::stringstream buf;
|
|
buf << "receiveStreamMessage - kick Peer" << pID;
|
|
//std::cerr << "buf " << buf << "\n";
|
|
DEBUG(buf.str().c_str());
|
|
|
|
if (pID == dis->getLocalPeer().getPeerID()) {
|
|
leaveGroup();
|
|
}//End if
|
|
else if (pID > INITIAL_FAKEID) {
|
|
// is a fade id;
|
|
meassuringRTT(pID, dat);
|
|
}//end else if
|
|
}
|
|
|
|
/**
|
|
* @brief method extract from a abuse peerId the sending item and calculate the rtt of a messages
|
|
* @param peerId, is a faked id. its the sendingtime + 1000
|
|
* @param dat, referennce of the message
|
|
*/
|
|
void
|
|
MaintanceApplication::meassuringRTT(PeerID peerId, const GroupData & dat) {
|
|
int sendTime = peerId.getValue() - INITIAL_FAKEID;
|
|
int reciveTime = GenericTime::currentTime().dbl() * MS_TO_INT_FACTOR;
|
|
int rtt = reciveTime - sendTime;
|
|
RTTStat.record(rtt);
|
|
MessageReference msgref = dat.getMessageReference();
|
|
DEBUG("rtt of msg " << msgref << " = " << rtt << "ms");
|
|
}
|
|
|
|
/**
|
|
* @brief methed create a fakepid
|
|
* @param value, parameter wich has to bo corvert to peerID
|
|
*/
|
|
PeerID
|
|
MaintanceApplication::createFakeID(unsigned int value) {
|
|
return PeerID(INITIAL_FAKEID + value);
|
|
}
|
|
|
|
/**
|
|
* @brief Handle an incoming MulticastMessageDroppedEvent.
|
|
* @param e The event.
|
|
*/
|
|
void MaintanceApplication::handleEvent(const MulticastMessageDroppedEvent& e) {
|
|
const MulticastMessage & msg = e.getMessage();
|
|
DEBUG("message " << msg << "(MREF=" << msg.getMessageReference() << ") is dropped !!!");
|
|
}
|
|
|
|
}
|
|
}
|
|
|