00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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");
00117 if (maliciousNodeRatio < (double) par("maliciousNodeChangeStartValue"))
00118 newRatio = (double) par("maliciousNodeChangeStartValue");
00119
00120 if (newRatio < (double) par("maliciousNodeChangeStopValue"))
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
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
00160
00161
00162 if (!node.isUnspecified()) {
00163 it = peerSet.find(node.getAddress());
00164
00165
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
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
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
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
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
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
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
00491 return NULL;
00492 } else {
00493
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
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