diff options
-rw-r--r-- | include/odhtdb/Database.hpp | 24 | ||||
-rw-r--r-- | include/odhtdb/DatabaseStorage.hpp | 9 | ||||
-rw-r--r-- | src/Database.cpp | 36 | ||||
-rw-r--r-- | src/DatabaseStorage.cpp | 24 |
4 files changed, 88 insertions, 5 deletions
diff --git a/include/odhtdb/Database.hpp b/include/odhtdb/Database.hpp index e78bc6e..ecdf70c 100644 --- a/include/odhtdb/Database.hpp +++ b/include/odhtdb/Database.hpp @@ -125,6 +125,24 @@ namespace odhtdb std::shared_ptr<OwnedMemory> key; std::shared_ptr<Hash> hash; }; + + struct DatabaseSeedInfo + { + std::shared_ptr<std::future<size_t>> newDataListenerFuture; + std::shared_ptr<std::future<size_t>> responseKeyFuture; + std::shared_ptr<std::future<size_t>> requestOldDataListenerFuture; + + std::shared_ptr<dht::InfoHash> reponseKeyInfoHash; + + DatabaseSeedInfo(){} + DatabaseSeedInfo(const DatabaseSeedInfo &other) + { + newDataListenerFuture = other.newDataListenerFuture; + responseKeyFuture = other.responseKeyFuture; + requestOldDataListenerFuture = other.requestOldDataListenerFuture; + reponseKeyInfoHash = other.reponseKeyInfoHash; + } + }; class Database { @@ -133,13 +151,16 @@ namespace odhtdb Database(const char *bootstrapNodeAddr, u16 port, const boost::filesystem::path &storageDir); ~Database(); + // Safe to call multiple times with same node hash, will be ignored if the node is already beeing seeded void seed(const DatabaseNode &nodeToSeed); + void stopSeeding(const Hash &nodeHash); + // Throws DatabaseCreateException on failure. std::unique_ptr<DatabaseCreateResponse> create(const std::string &ownerName, const std::string &nodeName); // Throws DatabaseCreateException on failure. std::unique_ptr<DatabaseCreateResponse> create(const std::string &ownerName, const Signature::KeyPair &keyPair, const std::string &nodeName); // Throws PermissionDeniedException if user @userToPerformActionWith is not allowed to add data to node - void addData(const DatabaseNode &nodeInfo, LocalUser *userToPerformActionWith, DataView dataToAdd); + void addData(const DatabaseNode &nodeInfo, const LocalUser *userToPerformActionWith, DataView dataToAdd); // Throws PermissionDeniedException if user @userToPerformActionWith is not allowed to add user @userToAdd to group @groupToAddUserTo void addUser(const DatabaseNode &nodeInfo, LocalUser *userToPerformActionWith, const std::string &userToAddName, const Signature::PublicKey &userToAddPublicKey, Group *groupToAddUserTo); void commit(); @@ -167,5 +188,6 @@ namespace odhtdb std::function<void(const DatabaseCreateNodeRequest&)> onCreateNodeCallbackFunc; std::function<void(const DatabaseAddNodeRequest&)> onAddNodeCallbackFunc; std::function<void(const DatabaseAddUserRequest&)> onAddUserCallbackFunc; + MapHash<DatabaseSeedInfo> seedInfoMap; }; } diff --git a/include/odhtdb/DatabaseStorage.hpp b/include/odhtdb/DatabaseStorage.hpp index 85a61eb..9cfe12d 100644 --- a/include/odhtdb/DatabaseStorage.hpp +++ b/include/odhtdb/DatabaseStorage.hpp @@ -140,9 +140,15 @@ namespace odhtdb // Returns nullptr if no storage with provided hash exists const DatabaseStorageObjectList* getStorage(const Hash &hash) const; + // Returns nullptr if node @nodeHash doesn't exist + const DataViewMap<Group*>* getNodeGroups(const Hash &nodeHash); + // Returns nullptr if a group with id @groupId doesn't exist in node @nodeHash or if no node with id @nodeHash exists Group* getGroupById(const Hash &nodeHash, uint8_t groupId[GROUP_ID_LENGTH]) const; + // Returns nullptr if node @nodeHash doesn't exist + const Signature::MapPublicKey<User*>* getNodeUsers(const Hash &nodeHash); + // Returns nullptr if a user with public key @publicKey doesn't exist in node @nodeHash or if no node with id @nodeHash exists User* getUserByPublicKey(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const; @@ -159,6 +165,9 @@ namespace odhtdb // Safe to call multiple times. std::vector<NodeLocalUser> getLocalNodeUsers(const Signature::KeyPair &keyPair); + // Returns true and node decryption key if node exists and we have the decryption key, + // otherwise return false and OwnedMemory with data set to nullptr + std::pair<bool, std::shared_ptr<OwnedMemory>> getNodeDecryptionKey(const Hash &nodeHash); void setNodeDecryptionKey(const Hash &nodeHash, const DataView &decryptionKey); const dht::crypto::Identity& getIdentity() const; diff --git a/src/Database.cpp b/src/Database.cpp index 6f864b4..7281025 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -140,6 +140,14 @@ namespace odhtdb void Database::seed(const DatabaseNode &nodeToSeed) { + if(seedInfoMap.find(*nodeToSeed.getRequestHash()) != seedInfoMap.end()) + { + Log::warn("You are already seeding node %s, ignoring...", nodeToSeed.getRequestHash()->toString().c_str()); + return; + } + + DatabaseSeedInfo newSeedInfo; + // TODO: Use cached files and seed those. If none exists, request new files to seed. // If nobody requests my cached files in a long time, request new files to seed and remove cached files // (only if there are plenty of other seeders for the cached files. This could also cause race issue @@ -150,7 +158,7 @@ namespace odhtdb Log::debug("Seeding key: %s", nodeToSeed.getRequestHash()->toString().c_str()); DhtKey dhtKey(*nodeToSeed.getRequestHash()); - node.listen(dhtKey.getNewDataListenerKey(), [this, nodeToSeed](const shared_ptr<Value> &value) + auto newDataListenerFuture = node.listen(dhtKey.getNewDataListenerKey(), [this, nodeToSeed](const shared_ptr<Value> &value) { Log::debug("Seed: New data listener received data..."); const Hash requestHash(value->data.data(), value->data.size()); @@ -160,12 +168,14 @@ namespace odhtdb else return listenAddData(value, requestHash, nodeToSeed.getRequestHash(), nodeToSeed.getNodeEncryptionKey()); }); + newSeedInfo.newDataListenerFuture = make_shared<future<size_t>>(move(newDataListenerFuture)); u8 responseKey[OPENDHT_INFOHASH_LEN]; randombytes_buf(responseKey, OPENDHT_INFOHASH_LEN); + newSeedInfo.reponseKeyInfoHash = make_shared<InfoHash>(responseKey, OPENDHT_INFOHASH_LEN); // TODO: If this response key is spammed, generate a new one. - node.listen(InfoHash(responseKey, OPENDHT_INFOHASH_LEN), [this, nodeToSeed](const shared_ptr<Value> &value) + auto responseKeyFuture = node.listen(*newSeedInfo.reponseKeyInfoHash, [this, nodeToSeed](const shared_ptr<Value> &value) { const Hash requestHash(value->data.data(), value->data.size()); if(requestHash == *nodeToSeed.getRequestHash()) @@ -173,10 +183,11 @@ namespace odhtdb else return listenAddData(value, requestHash, nodeToSeed.getRequestHash(), nodeToSeed.getNodeEncryptionKey()); }); + newSeedInfo.responseKeyFuture = make_shared<future<size_t>>(move(responseKeyFuture)); // TODO: Before listening on this key, we should check how many remote peers are also providing this data. // This is to prevent too many peers from responding to a request to get old data. - node.listen(dhtKey.getRequestOldDataKey(), [this, nodeToSeed](const shared_ptr<Value> &value) + auto requestOldDataListenerFuture = node.listen(dhtKey.getRequestOldDataKey(), [this, nodeToSeed](const shared_ptr<Value> &value) { Log::debug("Request: Got request to send old data"); try @@ -220,6 +231,9 @@ namespace odhtdb } return true; }); + newSeedInfo.requestOldDataListenerFuture = make_shared<future<size_t>>(move(requestOldDataListenerFuture)); + + seedInfoMap[*nodeToSeed.getRequestHash()] = newSeedInfo; sibs::SafeSerializer serializer; serializer.add((u64)0); // Timestamp in microseconds, fetch data newer than this. // TODO: Get timestamp from database storage @@ -233,6 +247,20 @@ namespace odhtdb //node.listen(CREATE_DATA_HASH, bind(&Database::listenCreateData, this, _1)); //node.listen(ADD_DATA_HASH, bind(&Database::listenAddData, this, _1)); } + + void Database::stopSeeding(const Hash &nodeHash) + { + auto seedInfoIt = seedInfoMap.find(nodeHash); + if(seedInfoIt != seedInfoMap.end()) + { + // TODO: Verify if doing get on listener future stalls program forever... Opendht documentation is not clear on this + DhtKey dhtKey(nodeHash); + node.cancelListen(dhtKey.getNewDataListenerKey(), seedInfoIt->second.newDataListenerFuture->get()); + node.cancelListen(dhtKey.getRequestOldDataKey(), seedInfoIt->second.requestOldDataListenerFuture->get()); + node.cancelListen(*seedInfoIt->second.reponseKeyInfoHash, seedInfoIt->second.responseKeyFuture->get()); + seedInfoMap.erase(seedInfoIt); + } + } unique_ptr<DatabaseCreateResponse> Database::create(const string &ownerName, const string &nodeName) { @@ -286,7 +314,7 @@ namespace odhtdb } } - void Database::addData(const DatabaseNode &nodeInfo, LocalUser *userToPerformActionWith, DataView dataToAdd) + void Database::addData(const DatabaseNode &nodeInfo, const LocalUser *userToPerformActionWith, DataView dataToAdd) { if(!userToPerformActionWith->isAllowedToPerformAction(PermissionType::ADD_DATA)) { diff --git a/src/DatabaseStorage.cpp b/src/DatabaseStorage.cpp index 0e9fa32..384ef5f 100644 --- a/src/DatabaseStorage.cpp +++ b/src/DatabaseStorage.cpp @@ -692,6 +692,14 @@ namespace odhtdb return nullptr; } + const DataViewMap<Group*>* DatabaseStorage::getNodeGroups(const Hash &nodeHash) + { + auto groupByIdMapIt = nodeGroupByIdMap.find(nodeHash); + if(groupByIdMapIt != nodeGroupByIdMap.end()) + return groupByIdMapIt->second; + return nullptr; + } + Group* DatabaseStorage::getGroupById(const Hash &nodeHash, uint8_t groupId[GROUP_ID_LENGTH]) const { auto groupByIdMapIt = nodeGroupByIdMap.find(nodeHash); @@ -704,6 +712,14 @@ namespace odhtdb return nullptr; } + const Signature::MapPublicKey<User*>* DatabaseStorage::getNodeUsers(const Hash &nodeHash) + { + auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); + if(publicKeyUserDataMapIt != nodePublicKeyUserDataMap.end()) + return publicKeyUserDataMapIt->second; + return nullptr; + } + User* DatabaseStorage::getUserByPublicKey(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const { auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); @@ -806,6 +822,14 @@ namespace odhtdb return localUsers; } + std::pair<bool, std::shared_ptr<OwnedMemory>> DatabaseStorage::getNodeDecryptionKey(const Hash &nodeHash) + { + auto nodeDecryptionKeyIt = nodeDecryptionKeyMap.find(nodeHash); + if(nodeDecryptionKeyIt != nodeDecryptionKeyMap.end()) + return make_pair(true, nodeDecryptionKeyIt->second); + return make_pair(false, make_shared<OwnedMemory>()); + } + void DatabaseStorage::setNodeDecryptionKey(const Hash &nodeHash, const DataView &decryptionKeyView) { bool nodeHasExistingEncryptionKey = nodeDecryptionKeyMap.find(nodeHash) != nodeDecryptionKeyMap.end(); |