A Distributed Hash Table (DHT) for KBR protocols. More...
#include <DHT.h>
Classes | |
class | PendingRpcsEntry |
Public Member Functions | |
DHT () | |
virtual | ~DHT () |
Private Types | |
enum | PendingRpcsStates { INIT = 0, LOOKUP_STARTED = 1, GET_HASH_SENT = 2, GET_VALUE_SENT = 3, PUT_SENT = 4 } |
typedef std::map< uint32_t, PendingRpcsEntry > | PendingRpcs |
Private Member Functions | |
void | initializeApp (int stage) |
initializes derived class-attributes | |
void | finishApp () |
collects statistical data of derived app | |
void | handleTimerEvent (cMessage *msg) |
bool | handleRpcCall (BaseCallMessage *msg) |
Processes Remote-Procedure-Call invocation messages. | |
void | handleRpcResponse (BaseResponseMessage *msg, cPolymorphic *context, int rpcId, simtime_t rtt) |
This method is called if an RPC response has been received. | |
void | handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, cPolymorphic *context, int rpcId, const OverlayKey &destKey) |
This method is called if an RPC timeout has been reached. | |
void | handlePutRequest (DHTPutCall *dhtMsg) |
void | handleGetRequest (DHTGetCall *dhtMsg) |
void | handlePutResponse (DHTPutResponse *dhtMsg, int rpcId) |
void | handleGetResponse (DHTGetResponse *dhtMsg, int rpcId) |
void | handlePutCAPIRequest (DHTputCAPICall *capiPutMsg) |
void | handleGetCAPIRequest (DHTgetCAPICall *capiPutMsg) |
void | handleDumpDhtRequest (DHTdumpCall *call) |
void | update (const NodeHandle &node, bool joined) |
Common API function: informs application about neighbors and own nodeID. | |
void | handleLookupResponse (LookupResponse *lookupMsg, int rpcId) |
void | sendMaintenancePutCall (const TransportAddress &dest, const OverlayKey &key, const DhtDataEntry &entry) |
int | resultValuesBitLength (DHTGetResponse *msg) |
Private Attributes | |
uint | numReplica |
int | numGetRequests |
double | ratioIdentical |
double | maintenanceMessages |
double | normalMessages |
double | numBytesMaintenance |
double | numBytesNormal |
bool | secureMaintenance |
use a secure maintenance algorithm based on majority decisions | |
bool | invalidDataAttack |
if node is malicious, it tries a invalidData attack | |
bool | maintenanceAttack |
if node is malicious, it tries a maintenanceData attack | |
PendingRpcs | pendingRpcs |
a map of all pending RPC operations | |
DHTDataStorage * | dataStorage |
pointer to the dht data storage | |
Friends | |
std::ostream & | operator<< (std::ostream &Stream, const PendingRpcsEntry &entry) |
A Distributed Hash Table (DHT) for KBR protocols.
A Distributed Hash Table (DHT) for KBR protocols
Definition at line 44 of file DHT.h.
typedef std::map<uint32_t, PendingRpcsEntry> DHT::PendingRpcs [private] |
enum DHT::PendingRpcsStates [private] |
Definition at line 51 of file DHT.h.
00051 { 00052 INIT = 0, 00053 LOOKUP_STARTED = 1, 00054 GET_HASH_SENT = 2, 00055 GET_VALUE_SENT = 3, 00056 PUT_SENT = 4 00057 };
DHT::DHT | ( | ) |
Definition at line 36 of file DHT.cc.
00037 { 00038 dataStorage = NULL; 00039 }
DHT::~DHT | ( | ) | [virtual] |
Definition at line 41 of file DHT.cc.
00042 { 00043 PendingRpcs::iterator it; 00044 00045 for (it = pendingRpcs.begin(); it != pendingRpcs.end(); it++) { 00046 delete(it->second.putCallMsg); 00047 delete(it->second.getCallMsg); 00048 } 00049 00050 pendingRpcs.clear(); 00051 00052 if (dataStorage != NULL) { 00053 dataStorage->clear(); 00054 } 00055 }
void DHT::finishApp | ( | ) | [private, virtual] |
collects statistical data of derived app
Reimplemented from BaseApp.
Definition at line 932 of file DHT.cc.
00933 { 00934 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime); 00935 00936 if (time >= GlobalStatistics::MIN_MEASURED) { 00937 globalStatistics->addStdDev("DHT: Sent Maintenance Messages/s", 00938 maintenanceMessages / time); 00939 globalStatistics->addStdDev("DHT: Sent Normal Messages/s", 00940 normalMessages / time); 00941 globalStatistics->addStdDev("DHT: Sent Maintenance Bytes/s", 00942 numBytesMaintenance / time); 00943 globalStatistics->addStdDev("DHT: Sent Normal Bytes/s", 00944 numBytesNormal / time); 00945 } 00946 }
void DHT::handleDumpDhtRequest | ( | DHTdumpCall * | call | ) | [private] |
Definition at line 515 of file DHT.cc.
Referenced by handleRpcCall().
00516 { 00517 DHTdumpResponse* response = new DHTdumpResponse(); 00518 DhtDumpVector* dumpVector = dataStorage->dumpDht(); 00519 00520 response->setRecordArraySize(dumpVector->size()); 00521 00522 for (uint32_t i = 0; i < dumpVector->size(); i++) { 00523 response->setRecord(i, (*dumpVector)[i]); 00524 } 00525 00526 delete dumpVector; 00527 00528 sendRpcResponse(call, response); 00529 }
void DHT::handleGetCAPIRequest | ( | DHTgetCAPICall * | capiPutMsg | ) | [private] |
Definition at line 501 of file DHT.cc.
Referenced by handleRpcCall().
00502 { 00503 LookupCall* lookupCall = new LookupCall(); 00504 lookupCall->setKey(capiGetMsg->getKey()); 00505 lookupCall->setNumSiblings(numReplica); 00506 sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0, 00507 capiGetMsg->getNonce()); 00508 00509 PendingRpcsEntry entry; 00510 entry.getCallMsg = capiGetMsg; 00511 entry.state = LOOKUP_STARTED; 00512 pendingRpcs.insert(make_pair(capiGetMsg->getNonce(), entry)); 00513 }
void DHT::handleGetRequest | ( | DHTGetCall * | dhtMsg | ) | [private] |
Definition at line 417 of file DHT.cc.
Referenced by handleRpcCall().
00418 { 00419 std::string tempString = "GET_REQUEST received: " 00420 + std::string(dhtMsg->getKey().toString(16)); 00421 00422 getParentModule()->getParentModule()->bubble(tempString.c_str()); 00423 00424 if (dhtMsg->getKey().isUnspecified()) { 00425 throw cRuntimeError("DHT::handleGetRequest: Unspecified key!"); 00426 } 00427 00428 DhtDumpVector* dataVect = dataStorage->dumpDht(dhtMsg->getKey(), 00429 dhtMsg->getKind(), 00430 dhtMsg->getId()); 00431 00432 if (overlay->isMalicious() && invalidDataAttack) { 00433 dataVect->resize(1); 00434 dataVect->at(0).setKey(dhtMsg->getKey()); 00435 dataVect->at(0).setKind(dhtMsg->getKind()); 00436 dataVect->at(0).setId(dhtMsg->getId()); 00437 dataVect->at(0).setValue("Modified Data"); 00438 dataVect->at(0).setTtl(3600*24*365); 00439 dataVect->at(0).setOwnerNode(overlay->getThisNode()); 00440 dataVect->at(0).setIs_modifiable(false); 00441 dataVect->at(0).setResponsible(true); 00442 } 00443 00444 // send back 00445 DHTGetResponse* responseMsg = new DHTGetResponse(); 00446 responseMsg->setKey(dhtMsg->getKey()); 00447 responseMsg->setIsHash(dhtMsg->getIsHash()); 00448 00449 if (dataVect->size() == 0) { 00450 responseMsg->setHashValue(BinaryValue::UNSPECIFIED_VALUE); 00451 responseMsg->setResultArraySize(0); 00452 } else { 00453 if (dhtMsg->getIsHash()) { 00454 // TODO: verify this 00455 BinaryValue resultValues; 00456 for (uint32_t i = 0; i < dataVect->size(); i++) { 00457 resultValues += (*dataVect)[i].getValue(); 00458 } 00459 00460 CSHA1 sha1; 00461 BinaryValue hashValue(20); 00462 sha1.Reset(); 00463 sha1.Update((uint8_t*) (&(*resultValues.begin())), 00464 resultValues.size()); 00465 sha1.Final(); 00466 sha1.GetHash((unsigned char*)&hashValue[0]); 00467 00468 responseMsg->setHashValue(hashValue); 00469 } else { 00470 responseMsg->setResultArraySize(dataVect->size()); 00471 00472 for (uint32_t i = 0; i < dataVect->size(); i++) { 00473 responseMsg->setResult(i, (*dataVect)[i]); 00474 } 00475 00476 } 00477 } 00478 delete dataVect; 00479 00480 responseMsg->setBitLength(GETRESPONSE_L(responseMsg)); 00481 RECORD_STATS(normalMessages++; 00482 numBytesNormal += responseMsg->getByteLength()); 00483 sendRpcResponse(dhtMsg, responseMsg); 00484 }
void DHT::handleGetResponse | ( | DHTGetResponse * | dhtMsg, | |
int | rpcId | |||
) | [private] |
Definition at line 555 of file DHT.cc.
Referenced by handleRpcResponse().
00556 { 00557 NodeVector* hashVector = NULL; 00558 PendingRpcs::iterator it = pendingRpcs.find(rpcId); 00559 00560 if (it == pendingRpcs.end()) // unknown request 00561 return; 00562 00563 if (it->second.state == GET_VALUE_SENT) { 00564 // we have sent a 'real' get request 00565 if (!dhtMsg->getIsHash()) { 00566 // TODO verify hash 00567 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse(); 00568 capiGetRespMsg->setResultArraySize(dhtMsg->getResultArraySize()); 00569 for (uint i = 0; i < dhtMsg->getResultArraySize(); i++) { 00570 capiGetRespMsg->setResult(i, dhtMsg->getResult(i)); 00571 } 00572 capiGetRespMsg->setIsSuccess(true); 00573 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg); 00574 pendingRpcs.erase(rpcId); 00575 return; 00576 } 00577 } 00578 00579 if (dhtMsg->getIsHash()) { 00580 std::map<BinaryValue, NodeVector>::iterator itHashes = 00581 it->second.hashes.find(dhtMsg->getHashValue()); 00582 00583 if (itHashes == it->second.hashes.end()) { 00584 // new hash 00585 NodeVector vect; 00586 vect.push_back(dhtMsg->getSrcNode()); 00587 it->second.hashes.insert(make_pair(dhtMsg->getHashValue(), 00588 vect)); 00589 } else { 00590 itHashes->second.push_back(dhtMsg->getSrcNode()); 00591 } 00592 00593 it->second.numResponses++; 00594 00595 if (it->second.state == GET_VALUE_SENT) { 00596 // we have already sent a real get request 00597 return; 00598 } 00599 00600 // count the maximum number of equal hash values received so far 00601 unsigned int maxCount = 0; 00602 00603 00604 for (itHashes = it->second.hashes.begin(); 00605 itHashes != it->second.hashes.end(); itHashes++) { 00606 00607 if (itHashes->second.size() > maxCount) { 00608 maxCount = itHashes->second.size(); 00609 hashVector = &(itHashes->second); 00610 } 00611 } 00612 00613 if ((double) maxCount / (double) it->second.numAvailableReplica 00614 >= ratioIdentical) { 00615 it->second.hashVector = hashVector; 00616 } else if (it->second.numResponses >= numGetRequests) { 00617 // we'll try to ask some other nodes 00618 if (it->second.replica.size() > 0) { 00619 DHTGetCall* getCall = new DHTGetCall(); 00620 getCall->setKey(dhtMsg->getKey()); 00621 getCall->setKind(dhtMsg->getKind()); 00622 getCall->setId(dhtMsg->getId()); 00623 getCall->setIsHash(true); 00624 getCall->setBitLength(GETCALL_L(getCall)); 00625 RECORD_STATS(normalMessages++; 00626 numBytesNormal += getCall->getByteLength()); 00627 sendRouteRpcCall(TIER1_COMP, 00628 it->second.replica.back(), getCall, 00629 NULL, DEFAULT_ROUTING, -1, 0, rpcId); 00630 it->second.replica.pop_back(); 00631 it->second.state = GET_HASH_SENT; 00632 } else if (hashVector == NULL) { 00633 // we don't have anyone else to ask and no hash 00634 DHTgetCAPIResponse* capiGetRespMsg = 00635 new DHTgetCAPIResponse(); 00636 DhtDumpEntry result; 00637 result.setKey(dhtMsg->getKey()); 00638 result.setValue(BinaryValue::UNSPECIFIED_VALUE); 00639 capiGetRespMsg->setResultArraySize(1); 00640 capiGetRespMsg->setResult(0, result); 00641 capiGetRespMsg->setIsSuccess(false); 00642 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg); 00643 #if 0 00644 cout << "DHT: GET failed: hash (no one else)" << endl; 00645 cout << "numResponses: " << it->second.numResponses 00646 << " numAvailableReplica: " << it->second.numAvailableReplica << endl; 00647 00648 for (itHashes = it->second.hashes.begin(); 00649 itHashes != it->second.hashes.end(); itHashes++) { 00650 cout << " - " << itHashes->first << " (" 00651 << itHashes->second.size() << ")" << endl; 00652 } 00653 #endif 00654 00655 pendingRpcs.erase(rpcId); 00656 return; 00657 } else { 00658 // we don't have anyone else to ask => take what we've got 00659 it->second.hashVector = hashVector; 00660 } 00661 } 00662 } 00663 00664 if ((it->second.state != GET_VALUE_SENT) && 00665 (it->second.hashVector != NULL)) { 00666 // we have already received all the response and chosen a hash 00667 if (it->second.hashVector->size() > 0) { 00668 DHTGetCall* getCall = new DHTGetCall(); 00669 getCall->setKey(it->second.getCallMsg->getKey()); 00670 getCall->setKind(it->second.getCallMsg->getKind()); 00671 getCall->setId(it->second.getCallMsg->getId()); 00672 getCall->setIsHash(false); 00673 getCall->setBitLength(GETCALL_L(getCall)); 00674 RECORD_STATS(normalMessages++; 00675 numBytesNormal += getCall->getByteLength()); 00676 sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(), 00677 getCall, NULL, DEFAULT_ROUTING, -1, 0, rpcId); 00678 it->second.hashVector->pop_back(); 00679 it->second.state = GET_VALUE_SENT; 00680 } else { // we don't have anyone else to ask 00681 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse(); 00682 DhtDumpEntry result; 00683 result.setKey(dhtMsg->getKey()); 00684 result.setValue(BinaryValue::UNSPECIFIED_VALUE); 00685 capiGetRespMsg->setResultArraySize(1); 00686 capiGetRespMsg->setResult(0, result); 00687 capiGetRespMsg->setIsSuccess(false); 00688 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg); 00689 //cout << "DHT: GET failed: hash2 (no one else)" << endl; 00690 pendingRpcs.erase(rpcId); 00691 } 00692 } 00693 }
void DHT::handleLookupResponse | ( | LookupResponse * | lookupMsg, | |
int | rpcId | |||
) | [private] |
Definition at line 810 of file DHT.cc.
Referenced by handleRpcResponse().
00811 { 00812 PendingRpcs::iterator it = pendingRpcs.find(rpcId); 00813 00814 if (it == pendingRpcs.end()) { 00815 return; 00816 } 00817 00818 if (it->second.putCallMsg != NULL) { 00819 00820 #if 0 00821 cout << "DHT::handleLookupResponse(): PUT " 00822 << lookupMsg->getKey() << " (" 00823 << overlay->getThisNode().getKey() << ")" << endl; 00824 00825 for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) { 00826 cout << i << ": " << lookupMsg->getSiblings(i) << endl; 00827 } 00828 #endif 00829 00830 if ((lookupMsg->getIsValid() == false) 00831 || (lookupMsg->getSiblingsArraySize() == 0)) { 00832 00833 EV << "[DHT::handleLookupResponse()]\n" 00834 << " Unable to get replica list : invalid lookup" 00835 << endl; 00836 DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse(); 00837 capiPutRespMsg->setIsSuccess(false); 00838 //cout << "DHT::lookup failed" << endl; 00839 sendRpcResponse(it->second.putCallMsg, capiPutRespMsg); 00840 pendingRpcs.erase(rpcId); 00841 return; 00842 } 00843 00844 if ((it->second.putCallMsg->getId() == 0) && 00845 (it->second.putCallMsg->getValue().size() > 0)) { 00846 // pick a random id before replication of the data item 00847 // id 0 is kept for delete requests (i.e. a put with empty value) 00848 it->second.putCallMsg->setId(intuniform(1, 2147483647)); 00849 } 00850 00851 for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) { 00852 DHTPutCall* dhtMsg = new DHTPutCall(); 00853 dhtMsg->setKey(it->second.putCallMsg->getKey()); 00854 dhtMsg->setKind(it->second.putCallMsg->getKind()); 00855 dhtMsg->setId(it->second.putCallMsg->getId()); 00856 dhtMsg->setValue(it->second.putCallMsg->getValue()); 00857 dhtMsg->setTtl(it->second.putCallMsg->getTtl()); 00858 dhtMsg->setIsModifiable(it->second.putCallMsg->getIsModifiable()); 00859 dhtMsg->setMaintenance(false); 00860 dhtMsg->setBitLength(PUTCALL_L(dhtMsg)); 00861 RECORD_STATS(normalMessages++; 00862 numBytesNormal += dhtMsg->getByteLength()); 00863 sendRouteRpcCall(TIER1_COMP, lookupMsg->getSiblings(i), 00864 dhtMsg, NULL, DEFAULT_ROUTING, -1, 00865 0, rpcId); 00866 } 00867 00868 it->second.state = PUT_SENT; 00869 it->second.numResponses = 0; 00870 it->second.numFailed = 0; 00871 it->second.numSent = lookupMsg->getSiblingsArraySize(); 00872 } 00873 else if (it->second.getCallMsg != NULL) { 00874 00875 #if 0 00876 cout << "DHT::handleLookupResponse(): GET " 00877 << lookupMsg->getKey() << " (" 00878 << overlay->getThisNode().getKey() << ")" << endl; 00879 00880 for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) { 00881 cout << i << ": " << lookupMsg->getSiblings(i) << endl; 00882 } 00883 #endif 00884 00885 if ((lookupMsg->getIsValid() == false) 00886 || (lookupMsg->getSiblingsArraySize() == 0)) { 00887 00888 EV << "[DHT::handleLookupResponse()]\n" 00889 << " Unable to get replica list : invalid lookup" 00890 << endl; 00891 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse(); 00892 DhtDumpEntry result; 00893 result.setKey(lookupMsg->getKey()); 00894 result.setValue(BinaryValue::UNSPECIFIED_VALUE); 00895 capiGetRespMsg->setResultArraySize(1); 00896 capiGetRespMsg->setResult(0, result); 00897 capiGetRespMsg->setIsSuccess(false); 00898 //cout << "DHT: lookup failed 2" << endl; 00899 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg); 00900 pendingRpcs.erase(rpcId); 00901 return; 00902 } 00903 00904 it->second.numSent = 0; 00905 00906 for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) { 00907 if (i < (unsigned int)numGetRequests) { 00908 DHTGetCall* dhtMsg = new DHTGetCall(); 00909 dhtMsg->setKey(it->second.getCallMsg->getKey()); 00910 dhtMsg->setKind(it->second.getCallMsg->getKind()); 00911 dhtMsg->setId(it->second.getCallMsg->getId()); 00912 dhtMsg->setIsHash(true); 00913 dhtMsg->setBitLength(GETCALL_L(dhtMsg)); 00914 RECORD_STATS(normalMessages++; 00915 numBytesNormal += dhtMsg->getByteLength()); 00916 sendRouteRpcCall(TIER1_COMP, lookupMsg->getSiblings(i), dhtMsg, 00917 NULL, DEFAULT_ROUTING, -1, 0, rpcId); 00918 it->second.numSent++; 00919 } else { 00920 // we don't send, we just store the remaining keys 00921 it->second.replica.push_back(lookupMsg->getSiblings(i)); 00922 } 00923 } 00924 00925 it->second.numAvailableReplica = lookupMsg->getSiblingsArraySize(); 00926 it->second.numResponses = 0; 00927 it->second.hashVector = NULL; 00928 it->second.state = GET_HASH_SENT; 00929 } 00930 }
void DHT::handlePutCAPIRequest | ( | DHTputCAPICall * | capiPutMsg | ) | [private] |
Definition at line 486 of file DHT.cc.
Referenced by handleRpcCall().
00487 { 00488 // asks the replica list 00489 LookupCall* lookupCall = new LookupCall(); 00490 lookupCall->setKey(capiPutMsg->getKey()); 00491 lookupCall->setNumSiblings(numReplica); 00492 sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0, 00493 capiPutMsg->getNonce()); 00494 00495 PendingRpcsEntry entry; 00496 entry.putCallMsg = capiPutMsg; 00497 entry.state = LOOKUP_STARTED; 00498 pendingRpcs.insert(make_pair(capiPutMsg->getNonce(), entry)); 00499 }
void DHT::handlePutRequest | ( | DHTPutCall * | dhtMsg | ) | [private] |
Definition at line 292 of file DHT.cc.
Referenced by handleRpcCall().
00293 { 00294 std::string tempString = "PUT_REQUEST received: " 00295 + std::string(dhtMsg->getKey().toString(16)); 00296 getParentModule()->getParentModule()->bubble(tempString.c_str()); 00297 00298 bool err; 00299 bool isSibling = overlay->isSiblingFor(overlay->getThisNode(), 00300 dhtMsg->getKey(), secureMaintenance ? numReplica : 1, &err); 00301 if (err) { 00302 isSibling = true; 00303 } 00304 00305 if (secureMaintenance && dhtMsg->getMaintenance()) { 00306 DhtDataEntry* entry = dataStorage->getDataEntry(dhtMsg->getKey(), 00307 dhtMsg->getKind(), 00308 dhtMsg->getId()); 00309 if (entry == NULL) { 00310 // add ttl timer 00311 DHTTtlTimer *timerMsg = new DHTTtlTimer("ttl_timer"); 00312 timerMsg->setKey(dhtMsg->getKey()); 00313 timerMsg->setKind(dhtMsg->getKind()); 00314 timerMsg->setId(dhtMsg->getId()); 00315 scheduleAt(simTime() + dhtMsg->getTtl(), timerMsg); 00316 00317 entry = dataStorage->addData(dhtMsg->getKey(), dhtMsg->getKind(), 00318 dhtMsg->getId(), dhtMsg->getValue(), timerMsg, 00319 dhtMsg->getIsModifiable(), dhtMsg->getSrcNode(), 00320 isSibling); 00321 } else if ((entry->siblingVote.size() == 0) && isSibling) { 00322 // we already have a verified entry with this key and are 00323 // still responsible => ignore maintenance calls 00324 delete dhtMsg; 00325 return; 00326 } 00327 00328 SiblingVoteMap::iterator it = entry->siblingVote.find(dhtMsg->getValue()); 00329 if (it == entry->siblingVote.end()) { 00330 // new hash 00331 NodeVector vect; 00332 vect.add(dhtMsg->getSrcNode()); 00333 entry->siblingVote.insert(make_pair(dhtMsg->getValue(), 00334 vect)); 00335 } else { 00336 it->second.add(dhtMsg->getSrcNode()); 00337 } 00338 00339 size_t maxCount = 0; 00340 SiblingVoteMap::iterator majorityIt; 00341 00342 for (it = entry->siblingVote.begin(); it != entry->siblingVote.end(); it++) { 00343 if (it->second.size() > maxCount) { 00344 maxCount = it->second.size(); 00345 majorityIt = it; 00346 } 00347 } 00348 00349 entry->value = majorityIt->first; 00350 entry->responsible = true; 00351 00352 if (maxCount > numReplica) { 00353 entry->siblingVote.clear(); 00354 } 00355 00356 // send back 00357 DHTPutResponse* responseMsg = new DHTPutResponse(); 00358 responseMsg->setSuccess(true); 00359 responseMsg->setBitLength(PUTRESPONSE_L(responseMsg)); 00360 RECORD_STATS(normalMessages++; numBytesNormal += responseMsg->getByteLength()); 00361 00362 sendRpcResponse(dhtMsg, responseMsg); 00363 00364 return; 00365 } 00366 00367 #if 0 00368 if (!(dataStorage->isModifiable(dhtMsg->getKey(), dhtMsg->getKind(), 00369 dhtMsg->getId()))) { 00370 // check if the put request came from the right node 00371 NodeHandle sourceNode = dataStorage->getSourceNode(dhtMsg->getKey(), 00372 dhtMsg->getKind(), dhtMsg->getId()); 00373 if (((!sourceNode.isUnspecified()) 00374 && (!dhtMsg->getSrcNode().isUnspecified()) && (sourceNode 00375 != dhtMsg->getSrcNode())) || ((dhtMsg->getMaintenance()) 00376 && (dhtMsg->getOwnerNode() == sourceNode))) { 00377 // TODO: set owner 00378 DHTPutResponse* responseMsg = new DHTPutResponse(); 00379 responseMsg->setSuccess(false); 00380 responseMsg->setBitLength(PUTRESPONSE_L(responseMsg)); 00381 RECORD_STATS(normalMessages++; 00382 numBytesNormal += responseMsg->getByteLength()); 00383 sendRpcResponse(dhtMsg, responseMsg); 00384 return; 00385 } 00386 00387 } 00388 #endif 00389 00390 // remove data item from local data storage 00391 dataStorage->removeData(dhtMsg->getKey(), dhtMsg->getKind(), 00392 dhtMsg->getId()); 00393 00394 if (dhtMsg->getValue().size() > 0) { 00395 // add ttl timer 00396 DHTTtlTimer *timerMsg = new DHTTtlTimer("ttl_timer"); 00397 timerMsg->setKey(dhtMsg->getKey()); 00398 timerMsg->setKind(dhtMsg->getKind()); 00399 timerMsg->setId(dhtMsg->getId()); 00400 scheduleAt(simTime() + dhtMsg->getTtl(), timerMsg); 00401 // storage data item in local data storage 00402 dataStorage->addData(dhtMsg->getKey(), dhtMsg->getKind(), 00403 dhtMsg->getId(), dhtMsg->getValue(), timerMsg, 00404 dhtMsg->getIsModifiable(), dhtMsg->getSrcNode(), 00405 isSibling); 00406 } 00407 00408 // send back 00409 DHTPutResponse* responseMsg = new DHTPutResponse(); 00410 responseMsg->setSuccess(true); 00411 responseMsg->setBitLength(PUTRESPONSE_L(responseMsg)); 00412 RECORD_STATS(normalMessages++; numBytesNormal += responseMsg->getByteLength()); 00413 00414 sendRpcResponse(dhtMsg, responseMsg); 00415 }
void DHT::handlePutResponse | ( | DHTPutResponse * | dhtMsg, | |
int | rpcId | |||
) | [private] |
Definition at line 531 of file DHT.cc.
Referenced by handleRpcResponse().
00532 { 00533 PendingRpcs::iterator it = pendingRpcs.find(rpcId); 00534 00535 if (it == pendingRpcs.end()) // unknown request 00536 return; 00537 00538 if (dhtMsg->getSuccess()) { 00539 it->second.numResponses++; 00540 } else { 00541 it->second.numFailed++; 00542 } 00543 00544 00545 // if ((it->second.numFailed + it->second.numResponses) == it->second.numSent) { 00546 if (it->second.numResponses / (double)it->second.numSent > 0.5) { 00547 00548 DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse(); 00549 capiPutRespMsg->setIsSuccess(true); 00550 sendRpcResponse(it->second.putCallMsg, capiPutRespMsg); 00551 pendingRpcs.erase(rpcId); 00552 } 00553 }
bool DHT::handleRpcCall | ( | BaseCallMessage * | msg | ) | [private, virtual] |
Processes Remote-Procedure-Call invocation messages.
This method should be overloaded when the overlay provides RPC functionality.
Reimplemented from BaseRpc.
Definition at line 105 of file DHT.cc.
00106 { 00107 RPC_SWITCH_START(msg) 00108 // RPCs between nodes 00109 RPC_DELEGATE(DHTPut, handlePutRequest); 00110 RPC_DELEGATE(DHTGet, handleGetRequest); 00111 // internal RPCs 00112 RPC_DELEGATE(DHTputCAPI, handlePutCAPIRequest); 00113 RPC_DELEGATE(DHTgetCAPI, handleGetCAPIRequest); 00114 RPC_DELEGATE(DHTdump, handleDumpDhtRequest); 00115 RPC_SWITCH_END( ) 00116 00117 return RPC_HANDLED; 00118 }
void DHT::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
cPolymorphic * | context, | |||
int | rpcId, | |||
simtime_t | rtt | |||
) | [private, virtual] |
This method is called if an RPC response has been received.
msg | The response message. | |
context | Pointer to an optional state object. The object has to be handled/deleted by the handleRpcResponse() code | |
rpcId | The RPC id. | |
rtt | The Round-Trip-Time of this RPC |
Reimplemented from RpcListener.
Definition at line 120 of file DHT.cc.
00122 { 00123 RPC_SWITCH_START(msg) 00124 RPC_ON_RESPONSE(DHTPut){ 00125 handlePutResponse(_DHTPutResponse, rpcId); 00126 EV << "[DHT::handleRpcResponse()]\n" 00127 << " DHT Put RPC Response received: id=" << rpcId 00128 << " msg=" << *_DHTPutResponse << " rtt=" << rtt 00129 << endl; 00130 break; 00131 } 00132 RPC_ON_RESPONSE(DHTGet) { 00133 handleGetResponse(_DHTGetResponse, rpcId); 00134 EV << "[DHT::handleRpcResponse()]\n" 00135 << " DHT Get RPC Response received: id=" << rpcId 00136 << " msg=" << *_DHTGetResponse << " rtt=" << rtt 00137 << endl; 00138 break; 00139 } 00140 RPC_ON_RESPONSE(Lookup) { 00141 handleLookupResponse(_LookupResponse, rpcId); 00142 EV << "[DHT::handleRpcResponse()]\n" 00143 << " Lookup RPC Response received: id=" << rpcId 00144 << " msg=" << *_LookupResponse << " rtt=" << rtt 00145 << endl; 00146 break; 00147 } 00148 RPC_SWITCH_END() 00149 }
void DHT::handleRpcTimeout | ( | BaseCallMessage * | msg, | |
const TransportAddress & | dest, | |||
cPolymorphic * | context, | |||
int | rpcId, | |||
const OverlayKey & | destKey | |||
) | [private, virtual] |
This method is called if an RPC timeout has been reached.
msg | The original RPC message. | |
dest | The destination node | |
context | Pointer to an optional state object. The object has to be handled/deleted by the handleRpcResponse() code | |
rpcId | The RPC id. | |
destKey | the destination OverlayKey |
Reimplemented from RpcListener.
Definition at line 151 of file DHT.cc.
00154 { 00155 RPC_SWITCH_START(msg) 00156 RPC_ON_CALL(DHTPut){ 00157 EV << "[DHT::handleRpcResponse()]\n" 00158 << " DHTPut Timeout" 00159 << endl; 00160 00161 PendingRpcs::iterator it = pendingRpcs.find(rpcId); 00162 00163 if (it == pendingRpcs.end()) // unknown request 00164 return; 00165 00166 it->second.numFailed++; 00167 00168 if (it->second.numFailed / (double)it->second.numSent >= 0.5) { 00169 DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse(); 00170 capiPutRespMsg->setIsSuccess(false); 00171 sendRpcResponse(it->second.putCallMsg, capiPutRespMsg); 00172 //cout << "timeout 1" << endl; 00173 pendingRpcs.erase(rpcId); 00174 } 00175 00176 break; 00177 } 00178 RPC_ON_CALL(DHTGet) { 00179 EV << "[DHT::handleRpcResponse()]\n" 00180 << " DHTGet Timeout" 00181 << endl; 00182 00183 PendingRpcs::iterator it = pendingRpcs.find(rpcId); 00184 00185 if (it == pendingRpcs.end()) { // unknown request 00186 return; 00187 } 00188 00189 if (it->second.state == GET_VALUE_SENT) { 00190 // we have sent a 'real' get request 00191 // ask anyone else, if possible 00192 if ((it->second.hashVector != NULL) 00193 && (it->second.hashVector->size() > 0)) { 00194 00195 DHTGetCall* getCall = new DHTGetCall(); 00196 getCall->setKey(_DHTGetCall->getKey()); 00197 getCall->setKind(_DHTGetCall->getKind()); 00198 getCall->setId(_DHTGetCall->getId()); 00199 getCall->setIsHash(false); 00200 getCall->setBitLength(GETCALL_L(getCall)); 00201 RECORD_STATS(normalMessages++; 00202 numBytesNormal += getCall->getByteLength()); 00203 00204 sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(), 00205 getCall, NULL, DEFAULT_ROUTING, -1, 0, rpcId); 00206 it->second.hashVector->pop_back(); 00207 } else { 00208 // no one else 00209 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse(); 00210 capiGetRespMsg->setIsSuccess(false); 00211 sendRpcResponse(it->second.getCallMsg, 00212 capiGetRespMsg); 00213 //cout << "DHT: GET failed: timeout (no one else)" << endl; 00214 pendingRpcs.erase(rpcId); 00215 return; 00216 } 00217 } else { 00218 // timeout while waiting for hashes 00219 // try to ask another one of the replica list for the hash 00220 if (it->second.replica.size() > 0) { 00221 DHTGetCall* getCall = new DHTGetCall(); 00222 getCall->setKey(_DHTGetCall->getKey()); 00223 getCall->setKind(_DHTGetCall->getKind()); 00224 getCall->setId(_DHTGetCall->getId()); 00225 getCall->setIsHash(true); 00226 getCall->setBitLength(GETCALL_L(getCall)); 00227 00228 RECORD_STATS(normalMessages++; 00229 numBytesNormal += getCall->getByteLength()); 00230 00231 sendRouteRpcCall(TIER1_COMP, it->second.replica.back(), 00232 getCall, NULL, DEFAULT_ROUTING, -1, 0, 00233 rpcId); 00234 it->second.replica.pop_back(); 00235 } else { 00236 // no one else to ask, see what we can do with what we have 00237 if (it->second.numResponses > 0) { 00238 unsigned int maxCount = 0; 00239 NodeVector* hashVector = NULL; 00240 std::map<BinaryValue, NodeVector>::iterator itHashes; 00241 for (itHashes = it->second.hashes.begin(); 00242 itHashes != it->second.hashes.end(); itHashes++) { 00243 00244 if (itHashes->second.size() > maxCount) { 00245 maxCount = itHashes->second.size(); 00246 hashVector = &(itHashes->second); 00247 } 00248 } 00249 00250 // since it makes no difference for us, if we 00251 // return a invalid result or return nothing, 00252 // we simply return the value with the highest probability 00253 it->second.hashVector = hashVector; 00254 #if 0 00255 if ((double)maxCount/(double)it->second.numResponses >= 00256 ratioIdentical) { 00257 it->second.hashVector = hashVector; 00258 } 00259 #endif 00260 } 00261 00262 if ((it->second.hashVector != NULL) 00263 && (it->second.hashVector->size() > 0)) { 00264 00265 DHTGetCall* getCall = new DHTGetCall(); 00266 getCall->setKey(_DHTGetCall->getKey()); 00267 getCall->setKind(_DHTGetCall->getKind()); 00268 getCall->setId(_DHTGetCall->getId()); 00269 getCall->setIsHash(false); 00270 getCall->setBitLength(GETCALL_L(getCall)); 00271 RECORD_STATS(normalMessages++; 00272 numBytesNormal += getCall->getByteLength()); 00273 sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(), 00274 getCall, NULL, DEFAULT_ROUTING, -1, 00275 0, rpcId); 00276 it->second.hashVector->pop_back(); 00277 } else { 00278 // no more nodes to ask -> get failed 00279 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse(); 00280 capiGetRespMsg->setIsSuccess(false); 00281 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg); 00282 //cout << "DHT: GET failed: timeout2 (no one else)" << endl; 00283 pendingRpcs.erase(rpcId); 00284 } 00285 } 00286 } 00287 break; 00288 } 00289 RPC_SWITCH_END( ) 00290 }
void DHT::handleTimerEvent | ( | cMessage * | msg | ) | [private, virtual] |
Reimplemented from BaseRpc.
Definition at line 88 of file DHT.cc.
00089 { 00090 DHTTtlTimer* msg_timer = dynamic_cast<DHTTtlTimer*> (msg); 00091 00092 if (msg_timer) { 00093 EV << "[DHT::handleTimerEvent()]\n" 00094 << " received timer ttl, key: " 00095 << msg_timer->getKey().toString(16) 00096 << "\n (overlay->getThisNode().getKey() = " 00097 << overlay->getThisNode().getKey().toString(16) << ")" 00098 << endl; 00099 00100 dataStorage->removeData(msg_timer->getKey(), msg_timer->getKind(), 00101 msg_timer->getId()); 00102 } 00103 }
void DHT::initializeApp | ( | int | stage | ) | [private, virtual] |
initializes derived class-attributes
stage | the init stage |
Reimplemented from BaseApp.
Definition at line 57 of file DHT.cc.
00058 { 00059 if (stage != MIN_STAGE_APP) 00060 return; 00061 00062 dataStorage = check_and_cast<DHTDataStorage*> 00063 (getParentModule()->getSubmodule("dhtDataStorage")); 00064 00065 numReplica = par("numReplica"); 00066 numGetRequests = par("numGetRequests"); 00067 ratioIdentical = par("ratioIdentical"); 00068 secureMaintenance = par("secureMaintenance"); 00069 invalidDataAttack = par("invalidDataAttack"); 00070 maintenanceAttack = par("maintenanceAttack"); 00071 00072 if ((int)numReplica > overlay->getMaxNumSiblings()) { 00073 opp_error("DHT::initialize(): numReplica bigger than what this " 00074 "overlay can handle (%d)", overlay->getMaxNumSiblings()); 00075 } 00076 00077 maintenanceMessages = 0; 00078 normalMessages = 0; 00079 numBytesMaintenance = 0; 00080 numBytesNormal = 0; 00081 WATCH(maintenanceMessages); 00082 WATCH(normalMessages); 00083 WATCH(numBytesNormal); 00084 WATCH(numBytesMaintenance); 00085 WATCH_MAP(pendingRpcs); 00086 }
int DHT::resultValuesBitLength | ( | DHTGetResponse * | msg | ) | [private] |
void DHT::sendMaintenancePutCall | ( | const TransportAddress & | dest, | |
const OverlayKey & | key, | |||
const DhtDataEntry & | entry | |||
) | [private] |
Definition at line 783 of file DHT.cc.
Referenced by update().
00785 { 00786 00787 DHTPutCall* dhtMsg = new DHTPutCall(); 00788 00789 dhtMsg->setKey(key); 00790 dhtMsg->setKind(entry.kind); 00791 dhtMsg->setId(entry.id); 00792 00793 if (overlay->isMalicious() && maintenanceAttack) { 00794 dhtMsg->setValue("Modified Data"); 00795 } else { 00796 dhtMsg->setValue(entry.value); 00797 } 00798 00799 dhtMsg->setTtl((int)SIMTIME_DBL(entry.ttlMessage->getArrivalTime() 00800 - simTime())); 00801 dhtMsg->setIsModifiable(entry.is_modifiable); 00802 dhtMsg->setMaintenance(true); 00803 dhtMsg->setBitLength(PUTCALL_L(dhtMsg)); 00804 RECORD_STATS(maintenanceMessages++; 00805 numBytesMaintenance += dhtMsg->getByteLength()); 00806 00807 sendRouteRpcCall(TIER1_COMP, node, dhtMsg); 00808 }
void DHT::update | ( | const NodeHandle & | node, | |
bool | joined | |||
) | [private, virtual] |
Common API function: informs application about neighbors and own nodeID.
node | new or lost neighbor | |
joined | new or lost? |
Reimplemented from BaseApp.
Definition at line 695 of file DHT.cc.
00696 { 00697 OverlayKey key; 00698 bool err = false; 00699 DhtDataEntry entry; 00700 std::map<OverlayKey, DhtDataEntry>::iterator it; 00701 00702 EV << "[DHT::update() @ " << overlay->getThisNode().getAddress() 00703 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n" 00704 << " Update called()" 00705 << endl; 00706 00707 if (secureMaintenance) { 00708 for (it = dataStorage->begin(); it != dataStorage->end(); it++) { 00709 if (it->second.responsible) { 00710 NodeVector* siblings = overlay->local_lookup(it->first, 00711 numReplica, 00712 false); 00713 if (siblings->size() == 0) { 00714 delete siblings; 00715 continue; 00716 } 00717 00718 if (joined) { 00719 EV << "[DHT::update() @ " << overlay->getThisNode().getAddress() 00720 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n" 00721 << " Potential new sibling for record " << it->first 00722 << endl; 00723 00724 if (overlay->distance(node.getKey(), it->first) <= 00725 overlay->distance(siblings->back().getKey(), it->first)) { 00726 00727 sendMaintenancePutCall(node, it->first, it->second); 00728 } 00729 00730 if (overlay->distance(overlay->getThisNode().getKey(), it->first) > 00731 overlay->distance(siblings->back().getKey(), it->first)) { 00732 00733 it->second.responsible = false; 00734 } 00735 } else { 00736 if (overlay->distance(node.getKey(), it->first) < 00737 overlay->distance(siblings->back().getKey(), it->first)) { 00738 00739 sendMaintenancePutCall(siblings->back(), it->first, 00740 it->second); 00741 } 00742 } 00743 00744 delete siblings; 00745 } 00746 } 00747 00748 return; 00749 } 00750 00751 for (it = dataStorage->begin(); it != dataStorage->end(); it++) { 00752 key = it->first; 00753 entry = it->second; 00754 if (joined) { 00755 if (entry.responsible && (overlay->isSiblingFor(node, key, 00756 numReplica, &err) 00757 || err)) { // hack for Chord, if we've got a new predecessor 00758 00759 if (err) { 00760 EV << "[DHT::update()]\n" 00761 << " Unable to know if key: " << key 00762 << " is in range of node: " << node 00763 << endl; 00764 // For Chord: we've got a new predecessor 00765 // TODO: only send record, if we are not responsible any more 00766 // TODO: check all protocols to change routing table first, 00767 // and than call update. 00768 00769 //if (overlay->isSiblingFor(overlay->getThisNode(), key, 1, &err)) { 00770 // continue; 00771 //} 00772 } 00773 00774 sendMaintenancePutCall(node, key, entry); 00775 } 00776 } 00777 //TODO: move this to the inner block above? 00778 entry.responsible = overlay->isSiblingFor(overlay->getThisNode(), 00779 key, 1, &err); 00780 } 00781 }
std::ostream& operator<< | ( | std::ostream & | Stream, | |
const PendingRpcsEntry & | entry | |||
) | [friend] |
Definition at line 957 of file DHT.cc.
00958 { 00959 if (entry.getCallMsg) { 00960 os << "GET"; 00961 } else if (entry.putCallMsg) { 00962 os << "PUT"; 00963 } 00964 00965 os << " state: " << entry.state 00966 << " numSent: " << entry.numSent 00967 << " numResponses: " << entry.numResponses 00968 << " numFailed: " << entry.numFailed 00969 << " numAvailableReplica: " << entry.numAvailableReplica; 00970 00971 if (entry.replica.size() > 0) { 00972 os << " replicaSize: " << entry.replica.size(); 00973 } 00974 00975 if (entry.hashVector != NULL) { 00976 os << " hashVectorSize: " << entry.hashVector->size(); 00977 } 00978 00979 if (entry.hashes.size() > 0) { 00980 os << " hashes:"; 00981 std::map<BinaryValue, NodeVector>::const_iterator it; 00982 00983 int i = 0; 00984 for (it = entry.hashes.begin(); it != entry.hashes.end(); it++, i++) { 00985 os << " hash" << i << ":" << it->second.size(); 00986 } 00987 } 00988 00989 return os; 00990 }
DHTDataStorage* DHT::dataStorage [private] |
pointer to the dht data storage
Definition at line 129 of file DHT.h.
Referenced by DHT(), handleDumpDhtRequest(), handleGetRequest(), handlePutRequest(), handleTimerEvent(), initializeApp(), update(), and ~DHT().
bool DHT::invalidDataAttack [private] |
if node is malicious, it tries a invalidData attack
Definition at line 122 of file DHT.h.
Referenced by handleGetRequest(), and initializeApp().
bool DHT::maintenanceAttack [private] |
if node is malicious, it tries a maintenanceData attack
Definition at line 123 of file DHT.h.
Referenced by initializeApp(), and sendMaintenancePutCall().
double DHT::maintenanceMessages [private] |
Definition at line 116 of file DHT.h.
Referenced by finishApp(), initializeApp(), and sendMaintenancePutCall().
double DHT::normalMessages [private] |
Definition at line 117 of file DHT.h.
Referenced by finishApp(), handleGetRequest(), handleGetResponse(), handleLookupResponse(), handlePutRequest(), handleRpcTimeout(), and initializeApp().
double DHT::numBytesMaintenance [private] |
Definition at line 118 of file DHT.h.
Referenced by finishApp(), initializeApp(), and sendMaintenancePutCall().
double DHT::numBytesNormal [private] |
Definition at line 119 of file DHT.h.
Referenced by finishApp(), handleGetRequest(), handleGetResponse(), handleLookupResponse(), handlePutRequest(), handleRpcTimeout(), and initializeApp().
int DHT::numGetRequests [private] |
Definition at line 114 of file DHT.h.
Referenced by handleGetResponse(), handleLookupResponse(), and initializeApp().
uint DHT::numReplica [private] |
Definition at line 113 of file DHT.h.
Referenced by handleGetCAPIRequest(), handlePutCAPIRequest(), handlePutRequest(), initializeApp(), and update().
PendingRpcs DHT::pendingRpcs [private] |
a map of all pending RPC operations
Definition at line 126 of file DHT.h.
Referenced by handleGetCAPIRequest(), handleGetResponse(), handleLookupResponse(), handlePutCAPIRequest(), handlePutResponse(), handleRpcTimeout(), initializeApp(), and ~DHT().
double DHT::ratioIdentical [private] |
Definition at line 115 of file DHT.h.
Referenced by handleGetResponse(), handleRpcTimeout(), and initializeApp().
bool DHT::secureMaintenance [private] |
use a secure maintenance algorithm based on majority decisions
Definition at line 121 of file DHT.h.
Referenced by handlePutRequest(), initializeApp(), and update().