/
githubmirror
/
aria2
Обзор
Документация
Войти
/
githubmirror
/
aria2
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/DHTBucket.cc
281 строка
8 KB
Tatsuhiro Tsujikawa
clang-format-5.0
23 ноя 2017, 08:11
23 ноя 2017, 08:11
795a047
Код
Авторство
О чём код?
/* <!-- copyright */ /* * aria2 - The high speed download utility * * Copyright (C) 2006 Tatsuhiro Tsujikawa * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /* copyright --> */ #include "DHTBucket.h" #include <cstring> #include <cassert> #include <algorithm> #include "DHTNode.h" #include "LogFactory.h" #include "Logger.h" #include "util.h" #include "DHTConstants.h" #include "a2functional.h" #include "bittorrent_helper.h" #include "bitfield.h" #include "wallclock.h" #include "fmt.h" namespace aria2 { DHTBucket::DHTBucket(size_t prefixLength, const unsigned char* max, const unsigned char* min, const std::shared_ptr<DHTNode>& localNode) : prefixLength_(prefixLength), localNode_(localNode), lastUpdated_(global::wallclock()) { memcpy(max_, max, DHT_ID_LENGTH); memcpy(min_, min, DHT_ID_LENGTH); } DHTBucket::DHTBucket(const std::shared_ptr<DHTNode>& localNode) : prefixLength_(0), localNode_(localNode), lastUpdated_(global::wallclock()) { memset(max_, 0xffu, DHT_ID_LENGTH); memset(min_, 0, DHT_ID_LENGTH); } DHTBucket::~DHTBucket() = default; void DHTBucket::getRandomNodeID(unsigned char* nodeID) const { if (prefixLength_ == 0) { util::generateRandomKey(nodeID); } else { size_t lastByteIndex = (prefixLength_ - 1) / 8; util::generateRandomKey(nodeID); memcpy(nodeID, min_, lastByteIndex + 1); } } bool DHTBucket::isInRange(const std::shared_ptr<DHTNode>& node) const { return isInRange(node->getID(), max_, min_); } bool DHTBucket::isInRange(const unsigned char* nodeID) const { return isInRange(nodeID, max_, min_); } // Returns true if nodeID is in [min, max] (inclusive). bool DHTBucket::isInRange(const unsigned char* nodeID, const unsigned char* max, const unsigned char* min) const { return !std::lexicographical_compare(&nodeID[0], &nodeID[DHT_ID_LENGTH], &min[0], &min[DHT_ID_LENGTH]) && !std::lexicographical_compare(&max[0], &max[DHT_ID_LENGTH], &nodeID[0], &nodeID[DHT_ID_LENGTH]); } bool DHTBucket::addNode(const std::shared_ptr<DHTNode>& node) { notifyUpdate(); auto itr = std::find_if(nodes_.begin(), nodes_.end(), derefEqual(node)); if (itr == nodes_.end()) { if (nodes_.size() < K) { nodes_.push_back(node); return true; } else { if (nodes_.front()->isBad()) { nodes_.erase(nodes_.begin()); nodes_.push_back(node); return true; } else { return false; } } } else { nodes_.erase(itr); nodes_.push_back(node); return true; } } void DHTBucket::cacheNode(const std::shared_ptr<DHTNode>& node) { // cachedNodes_ are sorted by last time seen cachedNodes_.push_front(node); if (cachedNodes_.size() > CACHE_SIZE) { cachedNodes_.resize(CACHE_SIZE, std::shared_ptr<DHTNode>()); } } void DHTBucket::dropNode(const std::shared_ptr<DHTNode>& node) { if (!cachedNodes_.empty()) { auto itr = std::find_if(nodes_.begin(), nodes_.end(), derefEqual(node)); if (itr != nodes_.end()) { nodes_.erase(itr); nodes_.push_back(cachedNodes_.front()); cachedNodes_.erase(cachedNodes_.begin()); } } } void DHTBucket::moveToHead(const std::shared_ptr<DHTNode>& node) { auto itr = std::find_if(nodes_.begin(), nodes_.end(), derefEqual(node)); if (itr != nodes_.end()) { nodes_.erase(itr); nodes_.push_front(node); } } void DHTBucket::moveToTail(const std::shared_ptr<DHTNode>& node) { auto itr = std::find_if(nodes_.begin(), nodes_.end(), derefEqual(node)); if (itr != nodes_.end()) { nodes_.erase(itr); nodes_.push_back(node); } } bool DHTBucket::splitAllowed() const { return prefixLength_ < DHT_ID_LENGTH * 8 - 1 && isInRange(localNode_); } std::unique_ptr<DHTBucket> DHTBucket::split() { assert(splitAllowed()); unsigned char rMax[DHT_ID_LENGTH]; memcpy(rMax, max_, DHT_ID_LENGTH); bitfield::flipBit(rMax, DHT_ID_LENGTH, prefixLength_); unsigned char rMin[DHT_ID_LENGTH]; memcpy(rMin, min_, DHT_ID_LENGTH); bitfield::flipBit(min_, DHT_ID_LENGTH, prefixLength_); ++prefixLength_; auto rBucket = make_unique<DHTBucket>(prefixLength_, rMax, rMin, localNode_); std::deque<std::shared_ptr<DHTNode>> lNodes; for (auto& elem : nodes_) { if (rBucket->isInRange(elem)) { assert(rBucket->addNode(elem)); } else { lNodes.push_back(elem); } } nodes_ = lNodes; // TODO create toString() and use it. A2_LOG_DEBUG(fmt("New bucket. prefixLength=%u, Range:%s-%s", static_cast<unsigned int>(rBucket->getPrefixLength()), util::toHex(rBucket->getMinID(), DHT_ID_LENGTH).c_str(), util::toHex(rBucket->getMaxID(), DHT_ID_LENGTH).c_str())); A2_LOG_DEBUG(fmt("Existing bucket. prefixLength=%u, Range:%s-%s", static_cast<unsigned int>(prefixLength_), util::toHex(getMinID(), DHT_ID_LENGTH).c_str(), util::toHex(getMaxID(), DHT_ID_LENGTH).c_str())); return rBucket; } void DHTBucket::getGoodNodes( std::vector<std::shared_ptr<DHTNode>>& goodNodes) const { goodNodes.insert(goodNodes.end(), nodes_.begin(), nodes_.end()); goodNodes.erase(std::remove_if(goodNodes.begin(), goodNodes.end(), std::mem_fn(&DHTNode::isBad)), goodNodes.end()); } std::shared_ptr<DHTNode> DHTBucket::getNode(const unsigned char* nodeID, const std::string& ipaddr, uint16_t port) const { auto node = std::make_shared<DHTNode>(nodeID); node->setIPAddress(ipaddr); node->setPort(port); auto itr = std::find_if(nodes_.begin(), nodes_.end(), derefEqual(node)); if (itr == nodes_.end() || (*itr)->getIPAddress() != ipaddr || (*itr)->getPort() != port) { return nullptr; } else { return *itr; } } bool DHTBucket::operator==(const DHTBucket& bucket) const { return memcmp(max_, bucket.max_, DHT_ID_LENGTH) == 0 && memcmp(min_, bucket.min_, DHT_ID_LENGTH) == 0; } bool DHTBucket::needsRefresh() const { return nodes_.size() < K || lastUpdated_.difference(global::wallclock()) >= DHT_BUCKET_REFRESH_INTERVAL; } void DHTBucket::notifyUpdate() { lastUpdated_ = global::wallclock(); } namespace { class FindQuestionableNode { public: bool operator()(const std::shared_ptr<DHTNode>& node) const { return node->isQuestionable(); } }; } // namespace bool DHTBucket::containsQuestionableNode() const { return std::find_if(nodes_.begin(), nodes_.end(), FindQuestionableNode()) != nodes_.end(); } std::shared_ptr<DHTNode> DHTBucket::getLRUQuestionableNode() const { auto i = std::find_if(nodes_.begin(), nodes_.end(), FindQuestionableNode()); if (i == nodes_.end()) { return nullptr; } else { return *i; } } } // namespace aria2