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

Generated on Tue Sep 8 17:26:52 2009 for OverSim by  doxygen 1.5.8