GlobalNodeList.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include <iostream>
00025 
00026 #include <omnetpp.h>
00027 
00028 #include <NotificationBoard.h>
00029 #include <BinaryValue.h>
00030 #include <OverlayKey.h>
00031 #include <PeerInfo.h>
00032 #include <BaseOverlay.h>
00033 #include <GlobalStatisticsAccess.h>
00034 #include <hashWatch.h>
00035 #include <BootstrapList.h>
00036 
00037 #include "GlobalNodeList.h"
00038 
00039 Define_Module(GlobalNodeList);
00040 
00041 std::ostream& operator<<(std::ostream& os, const BootstrapEntry entry)
00042 {
00043     NodeHandle* nodeHandle = dynamic_cast<NodeHandle*>(entry.node);
00044 
00045     os << "Address: " << entry.node->getIp()
00046        << " Port: " << entry.node->getPort();
00047 
00048     if (nodeHandle) {
00049         os << " NodeId: " << nodeHandle->getKey();
00050     }
00051 
00052     os << " ModuleID: "
00053        << entry.info->getModuleID() << " Bootstrapped: "
00054        << (entry.info->isBootstrapped() ? "true" : "false")
00055        << " NPS Layer: " << ((int) entry.info->getNpsLayer())
00056        << " TypeID: " << (entry.info->getTypeID());
00057 
00058     return os;
00059 }
00060 
00061 void GlobalNodeList::initialize()
00062 {
00063     maxNumberOfKeys = par("maxNumberOfKeys");
00064     keyProbability = par("keyProbability");
00065     isKeyListInitialized = false;
00066     WATCH_UNORDERED_MAP(peerStorage.getPeerHashMap());
00067     WATCH_VECTOR(keyList);
00068     WATCH(landmarkPeerSize);
00069 
00070     landmarkPeerSize = 0;
00071 
00072     for (int i = 0; i < MAX_NODETYPES; i++) {
00073         landmarkPeerSizePerType[i] = 0;
00074     }
00075 
00076     preKilledNodes = 0;
00077 
00078     if (par("maliciousNodeChange")) {
00079         if ((double) par("maliciousNodeProbability") > 0)
00080             error("maliciousNodeProbability and maliciousNodeChange are not supported concurrently");
00081 
00082         cMessage* msg = new cMessage("maliciousNodeChange");
00083         scheduleAt(simTime() + (int) par("maliciousNodeChangeStartTime"), msg);
00084         maliciousNodesVector.setName("MaliciousNodeRate");
00085         maliciousNodesVector.record(0);
00086         maliciousNodeRatio = 0;
00087     }
00088 
00089     for (int i=0; i<MAX_NODETYPES; i++) {
00090         for (int j=0; j<MAX_NODETYPES; j++) {
00091             connectionMatrix[i][j] = true;
00092         }
00093     }
00094 
00095     globalStatistics = GlobalStatisticsAccess().get();
00096 
00097     cMessage* timer = new cMessage("oracleTimer");
00098 
00099     scheduleAt(simTime(), timer);
00100 }
00101 
00102 void GlobalNodeList::handleMessage(cMessage* msg)
00103 {
00104     if (msg->isName("maliciousNodeChange")) {
00105         double newRatio = maliciousNodeRatio + (double) par("maliciousNodeChangeRate"); // ratio to obtain
00106         if (maliciousNodeRatio < (double) par("maliciousNodeChangeStartValue"))
00107             newRatio = (double) par("maliciousNodeChangeStartValue");
00108 
00109         if (newRatio < (double) par("maliciousNodeChangeStopValue")) // schedule next event
00110             scheduleAt(simTime() + (int) par("maliciousNodeChangeInterval"), msg);
00111 
00112         int nodesNeeded = (int) (((double) par("maliciousNodeChangeRate")) * peerStorage.size());
00113 
00114         EV << "[GlobalNodeList::handleMessage()]\n"
00115            << "    Changing " << nodesNeeded << " nodes to be malicious"
00116            << endl;
00117 
00118         for (int i = 0; i < nodesNeeded; i++) {
00119             // search a node that is not yet malicious
00120             NodeHandle node;
00121             do {
00122                 node = getRandomNode(0, false);
00123             } while (isMalicious(node));
00124 
00125             setMalicious(node, true);
00126         }
00127 
00128         maliciousNodesVector.record(newRatio);
00129         maliciousNodeRatio = newRatio;
00130 
00131         return;
00132     }
00133 
00134     else if (msg->isName("oracleTimer")) {
00135         RECORD_STATS(globalStatistics->recordOutVector(
00136                      "GlobalNodeList: Number of nodes", peerStorage.size()));
00137         scheduleAt(simTime() + 50, msg);
00138     } else {
00139         opp_error("GlobalNodeList::handleMessage: Unknown message type!");
00140     }
00141 }
00142 
00143 const NodeHandle& GlobalNodeList::getBootstrapNode(const NodeHandle &node)
00144 {
00145     uint32_t nodeType;
00146     PeerHashMap::iterator it;
00147 
00148     // always prefer boot node from the same TypeID
00149     // if there is no such node, go through all
00150     // connected partitions until a bootstrap node is found
00151     if (!node.isUnspecified()) {
00152         it = peerStorage.find(node.getIp());
00153 
00154         // this should never happen
00155         if (it == peerStorage.end()) {
00156            return getRandomNode(0, true);
00157         }
00158 
00159         nodeType = it->second.info->getTypeID();
00160         const NodeHandle &tempNode1 = getRandomNode(nodeType, true);
00161 
00162         if (tempNode1.isUnspecified()) {
00163             for (uint32_t i = 0; i < MAX_NODETYPES; i++) {
00164                 if (i == nodeType)
00165                     continue;
00166 
00167                 if (connectionMatrix[nodeType][i]) {
00168                     const NodeHandle &tempNode2 = getRandomNode(i, true);
00169                     if (!tempNode2.isUnspecified())
00170                         return tempNode2;
00171                 }
00172             }
00173             return NodeHandle::UNSPECIFIED_NODE;
00174         } else {
00175             return tempNode1;
00176         }
00177     } else {
00178         return getRandomNode(0, true);
00179     }
00180 }
00181 
00182 const NodeHandle& GlobalNodeList::getRandomNode(int32_t nodeType,
00183                                                 bool bootstrappedNeeded,
00184                                                 bool inoffensiveNeeded)
00185 {
00186     PeerHashMap::iterator it = peerStorage.getRandomNode(nodeType,
00187                                                          bootstrappedNeeded,
00188                                                          inoffensiveNeeded);
00189     if (it == peerStorage.end()) {
00190         return NodeHandle::UNSPECIFIED_NODE;
00191     }
00192 
00193     if (dynamic_cast<NodeHandle*>(it->second.node)) {
00194         return *dynamic_cast<NodeHandle*>(it->second.node);
00195     } else {
00196         return NodeHandle::UNSPECIFIED_NODE;
00197     }
00198 }
00199 
00200 void GlobalNodeList::sendNotificationToAllPeers(int category)
00201 {
00202     PeerHashMap::iterator it;
00203     for (it = peerStorage.begin(); it != peerStorage.end(); it++) {
00204         NotificationBoard* nb = check_and_cast<NotificationBoard*>(
00205                 simulation.getModule(it->second.info->getModuleID())
00206                 ->getSubmodule("notificationBoard"));
00207 
00208         nb->fireChangeNotification(category);
00209     }
00210 }
00211 
00212 void GlobalNodeList::addPeer(const IPvXAddress& ip, PeerInfo* info)
00213 {
00214     BootstrapEntry temp;
00215     temp.node = new TransportAddress(ip);
00216     temp.info = info;
00217     temp.info->setPreKilled(false);
00218 
00219     peerStorage.insert(std::make_pair(temp.node->getIp(), temp));
00220 
00221     if (uniform(0, 1) < (double) par("maliciousNodeProbability") ||
00222             (par("maliciousNodeChange") && uniform(0, 1) < maliciousNodeRatio)) {
00223         setMalicious(*temp.node, true);
00224     }
00225 
00226     if (peerStorage.size() == 1) {
00227         // we need at least one inoffensive bootstrap node
00228         setMalicious(*temp.node, false);
00229     }
00230 }
00231 
00232 void GlobalNodeList::registerPeer(const TransportAddress& peer)
00233 {
00234     PeerHashMap::iterator it = peerStorage.find(peer.getIp());
00235 
00236     if (it == peerStorage.end()) {
00237         throw cRuntimeError("GlobalNodeList::registerPeer(): "
00238                 "Peer is not in peer set");
00239     } else {
00240         delete it->second.node;
00241         it->second.node = new TransportAddress(peer);
00242         peerStorage.setBootstrapped(it, true);
00243     }
00244 }
00245 
00246 void GlobalNodeList::registerPeer(const NodeHandle& peer)
00247 {
00248     PeerHashMap::iterator it = peerStorage.find(peer.getIp());
00249 
00250     if (it == peerStorage.end()) {
00251         throw cRuntimeError("GlobalNodeList::registerPeer(): "
00252                 "Peer is not in peer set");
00253     } else {
00254         delete it->second.node;
00255         it->second.node = new NodeHandle(peer);
00256         peerStorage.setBootstrapped(it, true);
00257     }
00258 }
00259 
00260 void GlobalNodeList::refreshEntry(const TransportAddress& peer)
00261 {
00262     PeerHashMap::iterator it = peerStorage.find(peer.getIp());
00263 
00264     if (it == peerStorage.end()) {
00265         throw cRuntimeError("GlobalNodeList::refreshEntry(): "
00266                 "Peer is not in peer set");
00267     } else {
00268         delete it->second.node;
00269         it->second.node = new TransportAddress(peer);
00270     }
00271 }
00272 
00273 void GlobalNodeList::removePeer(const TransportAddress& peer)
00274 {
00275     PeerHashMap::iterator it = peerStorage.find(peer.getIp());
00276 
00277     if (it != peerStorage.end()) {
00278         peerStorage.setBootstrapped(it, false);
00279     }
00280 }
00281 
00282 void GlobalNodeList::killPeer(const IPvXAddress& ip)
00283 {
00284     PeerHashMap::iterator it = peerStorage.find(ip);
00285     if (it != peerStorage.end()) {
00286         if (it->second.info->isPreKilled()) {
00287             it->second.info->setPreKilled(false);
00288             preKilledNodes--;
00289         }
00290 
00291         // if valid NPS landmark: decrease landmarkPeerSize
00292         PeerInfo* peerInfo = it->second.info;
00293         if (peerInfo->getNpsLayer() > -1) {
00294             landmarkPeerSize--;
00295             landmarkPeerSizePerType[it->second.info->getTypeID()]--;
00296         }
00297 
00298         peerStorage.erase(it);
00299     }
00300 }
00301 
00302 PeerInfo* GlobalNodeList::getPeerInfo(const TransportAddress& peer)
00303 {
00304     return getPeerInfo(peer.getIp());
00305 }
00306 
00307 PeerInfo* GlobalNodeList::getPeerInfo(const IPvXAddress& ip)
00308 {
00309     PeerHashMap::iterator it = peerStorage.find(ip);
00310 
00311     if (it == peerStorage.end())
00312         return NULL;
00313     else
00314         return it->second.info;
00315 }
00316 
00317 PeerInfo* GlobalNodeList::getRandomPeerInfo(int32_t nodeType,
00318                                             bool bootstrappedNeeded)
00319 {
00320     PeerHashMap::iterator it = peerStorage.getRandomNode(nodeType,
00321                                                          bootstrappedNeeded,
00322                                                          false);
00323     if (it == peerStorage.end()) {
00324         return NULL;
00325     } else {
00326         return it->second.info;
00327     }
00328 }
00329 
00330 void GlobalNodeList::setPreKilled(const TransportAddress& address)
00331 {
00332     PeerInfo* peer = getPeerInfo(address);
00333 
00334     if ((peer != NULL) && !(peer->isPreKilled())) {
00335         preKilledNodes++;
00336         peer->setPreKilled(true);
00337     }
00338 }
00339 
00340 // TODO: this method should be removed in the future
00341 TransportAddress* GlobalNodeList::getRandomAliveNode(int32_t nodeType)
00342 {
00343     if (peerStorage.size() <= preKilledNodes) {
00344         // all nodes are already marked for deletion;
00345         return NULL;
00346     } else {
00347         PeerHashMap::iterator it = peerStorage.getRandomNode(nodeType, false,
00348                                                              false);
00349         while (it != peerStorage.end()) {
00350             if (!it->second.info->isPreKilled()) {
00351                 return it->second.node;
00352             } else {
00353                 it = peerStorage.getRandomNode(nodeType, false, false);
00354             }
00355         }
00356         return NULL;
00357     }
00358 }
00359 
00360 void GlobalNodeList::setMalicious(const TransportAddress& address, bool malicious)
00361 {
00362     peerStorage.setMalicious(peerStorage.find(address.getIp()), malicious);
00363 }
00364 
00365 bool GlobalNodeList::isMalicious(const TransportAddress& address)
00366 {
00367     PeerInfo* peer = getPeerInfo(address);
00368 
00369     if (peer != NULL) {
00370         return peer->isMalicious();
00371     }
00372 
00373     return false;
00374 }
00375 
00376 cObject** GlobalNodeList::getContext(const TransportAddress& address)
00377 {
00378     PeerInfo* peer = getPeerInfo(address);
00379 
00380     if (peer != NULL) {
00381         return peer->getContext();
00382     }
00383 
00384     return NULL;
00385 }
00386 
00387 void GlobalNodeList::setOverlayReadyIcon(const TransportAddress& address,
00388                                          bool ready)
00389 {
00390     if (ev.isGUI()) {
00391         const char* color;
00392 
00393         if (ready) {
00394             // change color if node is malicious
00395             color = isMalicious(address) ? "green" : "";
00396         } else {
00397             color = isMalicious(address) ? "yellow" : "red";
00398         }
00399 
00400         PeerInfo* info = getPeerInfo(address);
00401 
00402         if (info != NULL) {
00403             simulation.getModule(info->getModuleID())->
00404                     getDisplayString().setTagArg("i2", 1, color);
00405         }
00406     }
00407 }
00408 
00409 bool GlobalNodeList::areNodeTypesConnected(int32_t a, int32_t b)
00410 {
00411     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00412         throw cRuntimeError("GlobalNodeList::areNodeTypesConnected(): nodeType "
00413               "bigger then MAX_NODETYPES");
00414     }
00415 
00416     return connectionMatrix[a][b];
00417 }
00418 
00419 void GlobalNodeList::connectNodeTypes(int32_t a, int32_t b)
00420 {
00421     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00422         throw cRuntimeError("GlobalNodeList::connectNodeTypes(): nodeType "
00423               "bigger then MAX_NODETYPES");
00424     }
00425 
00426     connectionMatrix[a][b]=true;
00427 
00428     EV << "[GlobalNodeList::connectNodeTypes()]\n"
00429        << "    Connecting " << a << "->" << b
00430        << endl;
00431 
00432 }
00433 
00434 void GlobalNodeList::disconnectNodeTypes(int32_t a, int32_t b)
00435 {
00436     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00437         throw cRuntimeError("GlobalNodeList::disconnectNodeTypes(): nodeType "
00438               "bigger then MAX_NODETYPES");
00439     }
00440 
00441     connectionMatrix[a][b]=false;
00442 
00443     EV << "[GlobalNodeList::disconnectNodeTypes()]\n"
00444        << "    Disconnecting " << a << "->" << b
00445        << endl;
00446 
00447 }
00448 
00449 void GlobalNodeList::mergeBootstrapNodes(int toPartition, int fromPartition,
00450                                          int numNodes)
00451 {
00452     BootstrapList* bootstrapList =
00453         check_and_cast<BootstrapList*>(simulation.getModule(
00454             getRandomPeerInfo(toPartition, false)->getModuleID())->
00455             getSubmodule("bootstrapList"));
00456 
00457     bootstrapList->insertBootstrapCandidate(getRandomNode(fromPartition, true),
00458                                        DNSSD);
00459 }
00460 
00461 
00462 void GlobalNodeList::createKeyList(uint32_t size)
00463 {
00464     for (uint32_t i = 0; i < size; i++)
00465         keyList.push_back(OverlayKey::random());
00466 }
00467 
00468 GlobalNodeList::KeyList* GlobalNodeList::getKeyList(uint32_t maximumKeys)
00469 {
00470     if( !isKeyListInitialized ) createKeyList(maxNumberOfKeys);
00471     if (maximumKeys > keyList.size()) {
00472         maximumKeys = keyList.size();
00473     }
00474     // copy keylist to temporary keylist
00475     KeyList tmpKeyList;
00476     tmpKeyList.clear();
00477 
00478     for (uint32_t i=0; i < keyList.size(); i++) {
00479         tmpKeyList.push_back(keyList[i]);
00480     }
00481 
00482     KeyList* returnList = new KeyList;
00483 
00484     for (uint32_t i=0; i < ((float)maximumKeys * keyProbability); i++) {
00485         uint32_t index = intuniform(0, tmpKeyList.size()-1);
00486 
00487         returnList->push_back(tmpKeyList[index]);
00488         tmpKeyList.erase(tmpKeyList.begin()+index);
00489     }
00490 
00491     return returnList;
00492 }
00493 
00494 const OverlayKey& GlobalNodeList::getRandomKeyListItem()
00495 {
00496     if( !isKeyListInitialized ) createKeyList(maxNumberOfKeys);
00497     return keyList[intuniform(0,keyList.size()-1)];
00498 }