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->getAddress()
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 
00066     WATCH_UNORDERED_MAP(peerSet);
00067     WATCH_VECTOR(keyList);
00068     WATCH(bootstrappedPeerSize);
00069     WATCH(bootstrappedMaliciousNodes);
00070     WATCH(maliciousNodes);
00071     WATCH(landmarkPeerSize);
00072 
00073     createKeyList(maxNumberOfKeys);
00074     bootstrappedPeerSize = 0;
00075     landmarkPeerSize = 0;
00076 
00077     for (int i = 0; i < MAX_NODETYPES; i++) {
00078         bootstrappedPeerSizePerType[i] = 0;
00079         landmarkPeerSizePerType[i] = 0;
00080     }
00081 
00082     bootstrappedMaliciousNodes = 0;
00083     maliciousNodes = 0;
00084     preKilledNodes = 0;
00085 
00086     if (par("maliciousNodeChange")) {
00087         if ((double) par("maliciousNodeProbability") > 0)
00088             error("maliciousNodeProbability and maliciousNodeChange are not supported concurrently");
00089 
00090         cMessage* msg = new cMessage("maliciousNodeChange");
00091         scheduleAt(simTime() + (int) par("maliciousNodeChangeStartTime"), msg);
00092         maliciousNodesVector.setName("MaliciousNodeRate");
00093         maliciousNodesVector.record(0);
00094         maliciousNodeRatio = 0;
00095     }
00096 
00097     min_ip = 0xFFFFFFFF;
00098     max_ip = 0x00000000;
00099 
00100     for (int i=0; i<MAX_NODETYPES; i++) {
00101         for (int j=0; j<MAX_NODETYPES; j++) {
00102             connectionMatrix[i][j] = true;
00103         }
00104     }
00105 
00106     globalStatistics = GlobalStatisticsAccess().get();
00107 
00108     cMessage* timer = new cMessage("oracleTimer");
00109 
00110     scheduleAt(simTime(), timer);
00111 }
00112 
00113 void GlobalNodeList::handleMessage(cMessage* msg)
00114 {
00115     if (msg->isName("maliciousNodeChange")) {
00116         double newRatio = maliciousNodeRatio + (double) par("maliciousNodeChangeRate"); // ratio to obtain
00117         if (maliciousNodeRatio < (double) par("maliciousNodeChangeStartValue"))
00118             newRatio = (double) par("maliciousNodeChangeStartValue");
00119 
00120         if (newRatio < (double) par("maliciousNodeChangeStopValue")) // schedule next event
00121             scheduleAt(simTime() + (int) par("maliciousNodeChangeInterval"), msg);
00122 
00123         int nodesNeeded = (int) (((double) par("maliciousNodeChangeRate")) * peerSet.size());
00124 
00125         EV << "[GlobalNodeList::handleMessage()]\n"
00126            << "    Changing " << nodesNeeded << " nodes to be malicious"
00127            << endl;
00128 
00129         for (int i = 0; i < nodesNeeded; i++) {
00130             // search a node that is not yet malicious
00131             NodeHandle node;
00132             do {
00133                 node = getRandomNode(0, false);
00134             } while (isMalicious(node));
00135 
00136             setMalicious(node, true);
00137         }
00138 
00139         maliciousNodesVector.record(newRatio);
00140         maliciousNodeRatio = newRatio;
00141 
00142         return;
00143     }
00144 
00145     else if (msg->isName("oracleTimer")) {
00146         RECORD_STATS(globalStatistics->recordOutVector(
00147                      "GlobalNodeList: Number of nodes", peerSet.size()));
00148         RECORD_STATS(globalStatistics->recordOutVector(
00149                      "GlobalNodeList: Number of bootstrapped malicious nodes",
00150                      bootstrappedMaliciousNodes));
00151         scheduleAt(simTime() + 50, msg);
00152     } else {
00153         opp_error("GlobalNodeList::handleMessage: Unknown message type!");
00154     }
00155 }
00156 
00157 const NodeHandle& GlobalNodeList::getBootstrapNode(const NodeHandle &node)
00158 {
00159     uint32_t nodeType;
00160     PeerHashMap::iterator it;
00161 
00162     // always prefer boot node from the same partition
00163     // if there is no such node, go through all
00164     // connected partitions until a bootstrap node is found
00165     if (!node.isUnspecified()) {
00166         it = peerSet.find(node.getAddress());
00167 
00168         // this should never happen
00169         if (it == peerSet.end()) {
00170            return getRandomNode(0, true);
00171         }
00172 
00173         nodeType = it->second.info->getTypeID();
00174         const NodeHandle &tempNode1 = getRandomNode(nodeType, true);
00175 
00176         if (tempNode1.isUnspecified()) {
00177             for (uint32_t i = 1; i < MAX_NODETYPES; i++) {
00178                 if (i == nodeType)
00179                     continue;
00180 
00181                 if (connectionMatrix[nodeType][i]) {
00182                     const NodeHandle &tempNode2 = getRandomNode(i, true);
00183                     if (!tempNode2.isUnspecified())
00184                         return tempNode2;
00185                 }
00186             }
00187             return NodeHandle::UNSPECIFIED_NODE;
00188         } else {
00189             return tempNode1;
00190         }
00191     } else {
00192         return getRandomNode(0, true);
00193     }
00194 }
00195 
00196 const NodeHandle& GlobalNodeList::getRandomNode(uint32_t nodeType,
00197                                                 bool bootstrappedNeeded,
00198                                                 bool inoffensiveNeeded)
00199 {
00200     if (inoffensiveNeeded &&
00201             ((nodeType != 0) || (bootstrappedNeeded == false))) {
00202         throw cRuntimeError("GlobalNodeList::getRandomNode(): "
00203                             "inoffensiveNeeded must only be used "
00204                             "with nodeType = 0 and bootstrappedNeeded = true!");
00205     }
00206 
00207     if (peerSet.size() == 0)
00208         return NodeHandle::UNSPECIFIED_NODE;
00209     if (bootstrappedNeeded && bootstrappedPeerSize == 0)
00210         return NodeHandle::UNSPECIFIED_NODE;
00211     if (nodeType && bootstrappedPeerSizePerType[nodeType] == 0)
00212         return NodeHandle::UNSPECIFIED_NODE;
00213     if (inoffensiveNeeded &&
00214             (bootstrappedPeerSize - bootstrappedMaliciousNodes <= 0))
00215         return NodeHandle::UNSPECIFIED_NODE;
00216     else {
00217         // return random TransportAddress in O(log n)
00218         PeerHashMap::iterator it = peerSet.end();
00219         bootstrapEntry tempEntry = {NULL, NULL};
00220 
00221         while (it == peerSet.end() ||(nodeType && (it->second.info->getTypeID() != nodeType))
00222                 || (bootstrappedNeeded && !it->second.info->isBootstrapped())
00223                 || (inoffensiveNeeded && it->second.info->isMalicious())) {
00224 
00225             IPvXAddress randomAddr(intuniform(min_ip, max_ip));
00226 
00227             it = peerSet.find(randomAddr);
00228 
00229             if (it == peerSet.end()) {
00230                 it = peerSet.insert(std::make_pair(randomAddr,tempEntry)).first;
00231                 peerSet.erase(it++);
00232             }
00233 
00234             if (it == peerSet.end())
00235                 it = peerSet.begin();
00236         }
00237 
00238         if (dynamic_cast<NodeHandle*>(it->second.node)) {
00239             return *dynamic_cast<NodeHandle*>(it->second.node);
00240         } else {
00241             return NodeHandle::UNSPECIFIED_NODE;
00242         }
00243     }
00244 }
00245 
00246 void GlobalNodeList::sendNotificationToAllPeers(int category)
00247 {
00248     PeerHashMap::iterator it;
00249     for (it = peerSet.begin(); it != peerSet.end(); it++) {
00250         NotificationBoard* nb = check_and_cast<NotificationBoard*>(
00251                 simulation.getModule(it->second.info->getModuleID())
00252                 ->getSubmodule("notificationBoard"));
00253 
00254         nb->fireChangeNotification(category);
00255     }
00256 }
00257 
00258 void GlobalNodeList::addPeer(const IPvXAddress& ip, PeerInfo* info)
00259 {
00260     bootstrapEntry temp;
00261     temp.node = new TransportAddress(ip);
00262     temp.info = info;
00263     temp.info->setPreKilled(false);
00264 
00265     peerSet.insert(std::make_pair(temp.node->getAddress(), temp));
00266     // set bounds for random node retrieval
00267     // TODO: doesn't work with IPv6
00268     if (ip.get4().getInt() < min_ip) min_ip = ip.get4().getInt();
00269     if (ip.get4().getInt() > max_ip) max_ip = ip.get4().getInt();
00270 
00271     if (uniform(0, 1) < (double) par("maliciousNodeProbability") ||
00272             (par("maliciousNodeChange") && uniform(0, 1) < maliciousNodeRatio)) {
00273         setMalicious(*temp.node, true);
00274     }
00275 
00276     if (peerSet.size() == 1) {
00277         // we need at least one inoffensive bootstrap node
00278         setMalicious(*temp.node, false);
00279     }
00280 }
00281 
00282 void GlobalNodeList::registerPeer(const TransportAddress& peer)
00283 {
00284     PeerHashMap::iterator it = peerSet.find(peer.getAddress());
00285     if (it == peerSet.end())
00286         error("unable to bootstrap peer, peer is not in peer set");
00287     else {
00288         PeerInfo* info = it->second.info;
00289 
00290         if (!info->isBootstrapped()) {
00291             bootstrappedPeerSize++;
00292             bootstrappedPeerSizePerType[info->getTypeID()]++;
00293             info->setBootstrapped();
00294 
00295             if (info->isMalicious())
00296                 bootstrappedMaliciousNodes++;
00297         }
00298 
00299         delete it->second.node;
00300         peerSet.erase(it);
00301 
00302         bootstrapEntry temp;
00303         temp.node = new TransportAddress(peer);
00304         temp.info = info;
00305         peerSet.insert(std::make_pair(temp.node->getAddress(), temp));
00306     }
00307 }
00308 
00309 void GlobalNodeList::registerPeer(const NodeHandle& peer)
00310 {
00311     PeerHashMap::iterator it = peerSet.find(peer.getAddress());
00312     if (it == peerSet.end())
00313         error("unable to bootstrap peer, peer is not in peer set");
00314     else {
00315         PeerInfo* info = it->second.info;
00316 
00317         if (!info->isBootstrapped()) {
00318             bootstrappedPeerSize++;
00319             bootstrappedPeerSizePerType[info->getTypeID()]++;
00320             info->setBootstrapped();
00321 
00322             if (info->isMalicious())
00323                 bootstrappedMaliciousNodes++;
00324         }
00325 
00326         delete it->second.node;
00327         peerSet.erase(it);
00328 
00329         bootstrapEntry temp;
00330         temp.node = new NodeHandle(peer);
00331         temp.info = info;
00332         peerSet.insert(std::make_pair(temp.node->getAddress(), temp));
00333     }
00334 }
00335 
00336 void GlobalNodeList::refreshEntry(const TransportAddress& peer)
00337 {
00338     PeerHashMap::iterator it = peerSet.find(peer.getAddress());
00339     if (it == peerSet.end()) {
00340         error("unable to refresh entry, peer is not in peer set");
00341     } else {
00342         PeerInfo* info = it->second.info;
00343 
00344         delete it->second.node;
00345         peerSet.erase(it);
00346 
00347         bootstrapEntry temp;
00348         temp.node = new TransportAddress(peer);
00349         temp.info = info;
00350         peerSet.insert(std::make_pair(temp.node->getAddress(), temp));
00351     }
00352 }
00353 
00354 void GlobalNodeList::removePeer(const TransportAddress& peer)
00355 {
00356     PeerHashMap::iterator it = peerSet.find(peer.getAddress());
00357     if(it != peerSet.end() && it->second.info->isBootstrapped()) {
00358         bootstrappedPeerSize--;
00359         bootstrappedPeerSizePerType[it->second.info->getTypeID()]--;
00360         it->second.info->setBootstrapped(false);
00361 
00362         if(it->second.info->isMalicious())
00363             bootstrappedMaliciousNodes--;
00364 
00365         it->second.info->setBootstrapped(false);
00366     }
00367 }
00368 
00369 void GlobalNodeList::killPeer(const IPvXAddress& ip)
00370 {
00371     PeerHashMap::iterator it = peerSet.find(ip);
00372     if(it != peerSet.end()) {
00373         if(it->second.info->isBootstrapped()) {
00374             bootstrappedPeerSize--;
00375             bootstrappedPeerSizePerType[it->second.info->getTypeID()]--;
00376 
00377             if(it->second.info->isMalicious())
00378                 bootstrappedMaliciousNodes--;
00379 
00380             it->second.info->setBootstrapped(false);
00381         }
00382 
00383         if (it->second.info->isPreKilled()) {
00384             it->second.info->setPreKilled(false);
00385             preKilledNodes--;
00386         }
00387 
00388         // if valid NPS landmark: decrease landmarkPeerSize
00389         PeerInfo* peerInfo = getPeerInfo(ip);
00390         if (peerInfo->getNpsLayer() > -1) {
00391             landmarkPeerSize--;
00392             landmarkPeerSizePerType[it->second.info->getTypeID()]--;
00393         }
00394 
00395         delete it->second.node;
00396         delete it->second.info;
00397         peerSet.erase(it);
00398     }
00399 }
00400 
00401 void GlobalNodeList::createKeyList(uint32_t size)
00402 {
00403     for (uint32_t i = 0; i < size; i++)
00404         keyList.push_back(OverlayKey::random());
00405 }
00406 
00407 GlobalNodeList::KeyList* GlobalNodeList::getKeyList(uint32_t maximumKeys)
00408 {
00409     if (maximumKeys > keyList.size()) {
00410         maximumKeys = keyList.size();
00411     }
00412     // copy keylist to temporary keylist
00413     KeyList tmpKeyList;
00414     tmpKeyList.clear();
00415 
00416     for (uint32_t i=0; i < keyList.size(); i++) {
00417         tmpKeyList.push_back(keyList[i]);
00418     }
00419 
00420     KeyList* returnList = new KeyList;
00421 
00422     for (uint32_t i=0; i < ((float)maximumKeys * keyProbability); i++) {
00423         uint32_t index = intuniform(0, tmpKeyList.size()-1);
00424 
00425         returnList->push_back(tmpKeyList[index]);
00426         tmpKeyList.erase(tmpKeyList.begin()+index);
00427     }
00428 
00429     return returnList;
00430 }
00431 
00432 const OverlayKey& GlobalNodeList::getRandomKeyListItem() const
00433 {
00434     return keyList[intuniform(0,keyList.size()-1)];
00435 }
00436 
00437 PeerInfo* GlobalNodeList::getPeerInfo(const TransportAddress& peer)
00438 {
00439     PeerHashMap::iterator it = peerSet.find(peer.getAddress());
00440 
00441     if (it == peerSet.end())
00442         return NULL;
00443     else
00444         return it->second.info;
00445 }
00446 
00447 PeerInfo* GlobalNodeList::getPeerInfo(const IPvXAddress& ip)
00448 {
00449     PeerHashMap::iterator it = peerSet.find(ip);
00450 
00451     if (it == peerSet.end())
00452         return NULL;
00453     else
00454         return it->second.info;
00455 }
00456 
00457 PeerInfo* GlobalNodeList::getRandomPeerInfo(uint32_t nodeType,
00458                                              bool bootstrappedNeeded) {
00459     // return random TransportAddress in O(log n)
00460     PeerHashMap::iterator it;
00461     bootstrapEntry tempEntry = {NULL, NULL};
00462 
00463     IPvXAddress randomAddr(intuniform(min_ip, max_ip));
00464 
00465     it = peerSet.find(randomAddr);
00466     if (it == peerSet.end()) {
00467         it = peerSet.insert(std::make_pair(randomAddr,tempEntry)).first;
00468         peerSet.erase(it++);
00469     }
00470 
00471     if (it == peerSet.end())
00472         it = peerSet.begin();
00473 
00474     // if nodeType != 0, search for next node with the given type
00475     if (nodeType) {
00476         while((nodeType && (it->second.info->getTypeID() != nodeType))
00477               || (bootstrappedNeeded && !it->second.info->isBootstrapped())) {
00478             ++it;
00479             if (it == peerSet.end()) it = peerSet.begin();
00480         }
00481     }
00482 
00483     return it->second.info;
00484 }
00485 
00486 void GlobalNodeList::setPreKilled(const TransportAddress& address)
00487 {
00488     PeerInfo* peer = getPeerInfo(address);
00489 
00490     if ((peer != NULL) && !(peer->isPreKilled())) {
00491         preKilledNodes++;
00492         peer->setPreKilled(true);
00493     }
00494 }
00495 
00496 TransportAddress* GlobalNodeList::getRandomAliveNode(uint32_t nodeType)
00497 {
00498     if (peerSet.size() <= preKilledNodes) {
00499         // all nodes are already marked for deletion;
00500         return NULL;
00501     } else {
00502         // return random address in O(log n)
00503         PeerHashMap::iterator it;
00504         bootstrapEntry tempEntry = {NULL, NULL};
00505 
00506         IPvXAddress randomAddr(intuniform(min_ip, max_ip));
00507 
00508         it = peerSet.find(randomAddr);
00509 
00510         if (it == peerSet.end()) {
00511             it = peerSet.insert(std::make_pair(randomAddr,tempEntry)).first;
00512             peerSet.erase(it++);
00513         }
00514 
00515         if (it == peerSet.end()) {
00516             it = peerSet.begin();
00517         }
00518 
00519         while ((nodeType && (it->second.info->getTypeID() != nodeType))
00520                || it->second.info->isPreKilled()) {
00521             it++;
00522             if (it == peerSet.end()) {
00523                 it = peerSet.begin();
00524             }
00525         }
00526 
00527         return it->second.node;
00528     }
00529 
00530     return NULL;
00531 }
00532 
00533 void GlobalNodeList::setMalicious(const TransportAddress& address, bool malicious)
00534 {
00535     PeerInfo* peer = getPeerInfo(address);
00536 
00537     if (peer != NULL) {
00538         if(malicious && !peer->isMalicious()) {
00539             maliciousNodes++;
00540             if (peer->isBootstrapped()) {
00541                 bootstrappedMaliciousNodes++;
00542             }
00543         }
00544 
00545         if (!malicious && peer->isMalicious()) {
00546             maliciousNodes--;
00547             if (peer->isBootstrapped()) {
00548                 bootstrappedMaliciousNodes--;
00549             }
00550         }
00551         peer->setMalicious(malicious);
00552     }
00553 }
00554 
00555 bool GlobalNodeList::isMalicious(const TransportAddress& address)
00556 {
00557     PeerInfo* peer = getPeerInfo(address);
00558 
00559     if(peer != NULL)
00560         return peer->isMalicious();
00561 
00562     return false;
00563 }
00564 
00565 cObject** GlobalNodeList::getContext(const TransportAddress& address)
00566 {
00567     PeerInfo* peer = getPeerInfo(address);
00568 
00569     if(peer != NULL)
00570         return peer->getContext();
00571 
00572     return NULL;
00573 }
00574 
00575 void GlobalNodeList::setOverlayReadyIcon(const TransportAddress& address,
00576         bool ready)
00577 {
00578     if (ev.isGUI()) {
00579         const char* color;
00580 
00581         if (ready) {
00582             // change color if node is malicious
00583             color = isMalicious(address) ? "green" : "";
00584         } else {
00585             color = isMalicious(address) ? "yellow" : "red";
00586         }
00587 
00588         PeerInfo* info = getPeerInfo(address);
00589 
00590         if(info != NULL) {
00591             simulation.getModule(info->getModuleID())
00592             ->getDisplayString().setTagArg("i2", 1, color);
00593         }
00594     }
00595 }
00596 
00597 bool GlobalNodeList::areNodeTypesConnected(uint32_t a, uint32_t b)
00598 {
00599     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00600         throw cRuntimeError("GlobalNodeList::areNodeTypesConnected(): nodeType "
00601               "bigger then MAX_NODETYPES");
00602     }
00603 
00604     return connectionMatrix[a][b];
00605 }
00606 
00607 void GlobalNodeList::connectNodeTypes(uint32_t a, uint32_t b)
00608 {
00609     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00610         throw cRuntimeError("GlobalNodeList::connectNodeTypes(): nodeType "
00611               "bigger then MAX_NODETYPES");
00612     }
00613 
00614     connectionMatrix[a][b]=true;
00615 
00616     EV << "[GlobalNodeList::connectNodeTypes()]\n"
00617        << "    Connecting " << a << "->" << b
00618        << endl;
00619 
00620 }
00621 
00622 void GlobalNodeList::disconnectNodeTypes(uint32_t a, uint32_t b)
00623 {
00624     if ((a > MAX_NODETYPES) || (b > MAX_NODETYPES)) {
00625         throw cRuntimeError("GlobalNodeList::disconnectNodeTypes(): nodeType "
00626               "bigger then MAX_NODETYPES");
00627     }
00628 
00629     connectionMatrix[a][b]=false;
00630 
00631     EV << "[GlobalNodeList::disconnectNodeTypes()]\n"
00632        << "    Disconnecting " << a << "->" << b
00633        << endl;
00634 
00635 }
00636 
00637 void GlobalNodeList::mergeBootstrapNodes(int toPartition, int fromPartition,
00638                                           int numNodes)
00639 {
00640     BootstrapList* bootstrapList =
00641         check_and_cast<BootstrapList*>(simulation.getModule(
00642             getRandomPeerInfo(toPartition, false)->getModuleID())->
00643             getSubmodule("bootstrapList"));
00644 
00645     bootstrapList->insertBootstrapCandidate(getRandomNode(fromPartition, true),
00646                                        DNSSD);
00647 }
00648 
00649 GlobalNodeList::~GlobalNodeList()
00650 {
00651     PeerHashMap::iterator it;
00652     for(it = peerSet.begin(); it != peerSet.end(); ++it) {
00653         delete it->second.node;
00654         delete it->second.info;
00655     }
00656 }
00657 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3