/* */ #include "DHTPeerAnnounceStorage.h" #include #include #include "DHTPeerAnnounceEntry.h" #include "Peer.h" #include "DHTConstants.h" #include "DHTTaskQueue.h" #include "DHTTaskFactory.h" #include "DHTTask.h" #include "LogFactory.h" #include "Logger.h" #include "util.h" #include "a2functional.h" #include "wallclock.h" #include "fmt.h" namespace aria2 { DHTPeerAnnounceStorage::DHTPeerAnnounceStorage() : taskQueue_{nullptr}, taskFactory_{nullptr} { } bool DHTPeerAnnounceStorage::InfoHashLess:: operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) { return memcmp(lhs->getInfoHash(), rhs->getInfoHash(), DHT_ID_LENGTH) < 0; } std::shared_ptr DHTPeerAnnounceStorage::getPeerAnnounceEntry(const unsigned char* infoHash) { auto entry = std::make_shared(infoHash); auto i = entries_.lower_bound(entry); if (i != entries_.end() && memcmp(infoHash, (*i)->getInfoHash(), DHT_ID_LENGTH) == 0) { entry = *i; } else { entries_.insert(i, entry); } return entry; } void DHTPeerAnnounceStorage::addPeerAnnounce(const unsigned char* infoHash, const std::string& ipaddr, uint16_t port) { A2_LOG_DEBUG(fmt("Adding %s:%u to peer announce list: infoHash=%s", ipaddr.c_str(), port, util::toHex(infoHash, DHT_ID_LENGTH).c_str())); getPeerAnnounceEntry(infoHash)->addPeerAddrEntry(PeerAddrEntry(ipaddr, port)); } bool DHTPeerAnnounceStorage::contains(const unsigned char* infoHash) const { auto entry = std::make_shared(infoHash); return std::binary_search(entries_.begin(), entries_.end(), entry, InfoHashLess()); } void DHTPeerAnnounceStorage::getPeers(std::vector>& peers, const unsigned char* infoHash) { auto entry = std::make_shared(infoHash); auto i = entries_.find(entry); if (i != entries_.end()) { (*i)->getPeers(peers); } } void DHTPeerAnnounceStorage::handleTimeout() { A2_LOG_DEBUG(fmt("Now purge peer announces(%lu entries) which are timed out.", static_cast(entries_.size()))); std::for_each(std::begin(entries_), std::end(entries_), [](const std::shared_ptr& e) { e->removeStalePeerAddrEntry(DHT_PEER_ANNOUNCE_PURGE_INTERVAL); }); for (auto i = std::begin(entries_); i != std::end(entries_);) { if ((*i)->empty()) { entries_.erase(i++); } else { ++i; } } A2_LOG_DEBUG(fmt("Currently %lu peer announce entries", static_cast(entries_.size()))); } void DHTPeerAnnounceStorage::announcePeer() { A2_LOG_DEBUG("Now announcing peer."); for (auto& e : entries_) { if (e->getLastUpdated().difference(global::wallclock()) < DHT_PEER_ANNOUNCE_INTERVAL) { continue; } e->notifyUpdate(); auto task = taskFactory_->createPeerAnnounceTask(e->getInfoHash()); taskQueue_->addPeriodicTask2(task); A2_LOG_DEBUG(fmt("Added 1 peer announce: infoHash=%s", util::toHex(e->getInfoHash(), DHT_ID_LENGTH).c_str())); } } void DHTPeerAnnounceStorage::setTaskQueue(DHTTaskQueue* taskQueue) { taskQueue_ = taskQueue; } void DHTPeerAnnounceStorage::setTaskFactory(DHTTaskFactory* taskFactory) { taskFactory_ = taskFactory; } } // namespace aria2