danicoin/src/P2p/PeerListManager.cpp
2016-01-18 15:33:29 +00:00

263 lines
7.5 KiB
C++
Executable file

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "PeerListManager.h"
#include <time.h>
#include <boost/foreach.hpp>
#include <System/Ipv4Address.h>
#include "Serialization/SerializationOverloads.h"
using namespace CryptoNote;
namespace CryptoNote {
template <typename T, typename Indexes>
bool serialize(boost::multi_index_container<T, Indexes>& value, Common::StringView name, ISerializer& s) {
if (s.type() == ISerializer::INPUT) {
readSequence<T>(std::inserter(value, value.end()), name, s);
} else {
writeSequence<T>(value.begin(), value.end(), name, s);
}
return true;
}
void serialize(NetworkAddress& na, ISerializer& s) {
s(na.ip, "ip");
s(na.port, "port");
}
void serialize(PeerlistEntry& pe, ISerializer& s) {
s(pe.adr, "adr");
s(pe.id, "id");
s(pe.last_seen, "last_seen");
}
}
PeerlistManager::Peerlist::Peerlist(peers_indexed& peers, size_t maxSize) :
m_peers(peers), m_maxSize(maxSize) {
}
void PeerlistManager::serialize(ISerializer& s) {
const uint8_t currentVersion = 1;
uint8_t version = currentVersion;
s(version, "version");
if (version != currentVersion) {
return;
}
s(m_peers_white, "whitelist");
s(m_peers_gray, "graylist");
}
size_t PeerlistManager::Peerlist::count() const {
return m_peers.size();
}
bool PeerlistManager::Peerlist::get(PeerlistEntry& entry, size_t i) const {
if (i >= m_peers.size())
return false;
peers_indexed::index<by_time>::type& by_time_index = m_peers.get<by_time>();
auto it = by_time_index.rbegin();
std::advance(it, i);
entry = *it;
return true;
}
void PeerlistManager::Peerlist::trim() {
peers_indexed::index<by_time>::type& sorted_index = m_peers.get<by_time>();
while (m_peers.size() > m_maxSize) {
sorted_index.erase(sorted_index.begin());
}
}
PeerlistManager::PeerlistManager() :
m_whitePeerlist(m_peers_white, CryptoNote::P2P_LOCAL_WHITE_PEERLIST_LIMIT),
m_grayPeerlist(m_peers_gray, CryptoNote::P2P_LOCAL_GRAY_PEERLIST_LIMIT) {}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::init(bool allow_local_ip)
{
m_allow_local_ip = allow_local_ip;
return true;
}
//--------------------------------------------------------------------------------------------------
void PeerlistManager::trim_white_peerlist() {
m_whitePeerlist.trim();
}
//--------------------------------------------------------------------------------------------------
void PeerlistManager::trim_gray_peerlist() {
m_grayPeerlist.trim();
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::merge_peerlist(const std::list<PeerlistEntry>& outer_bs)
{
for(const PeerlistEntry& be : outer_bs) {
append_with_peer_gray(be);
}
// delete extra elements
trim_gray_peerlist();
return true;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::get_white_peer_by_index(PeerlistEntry& p, size_t i) const {
return m_whitePeerlist.get(p, i);
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::get_gray_peer_by_index(PeerlistEntry& p, size_t i) const {
return m_grayPeerlist.get(p, i);
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::is_ip_allowed(uint32_t ip) const
{
System::Ipv4Address addr(networkToHost(ip));
//never allow loopback ip
if (addr.isLoopback()) {
return false;
}
if (!m_allow_local_ip && addr.isPrivate()) {
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::get_peerlist_head(std::list<PeerlistEntry>& bs_head, uint32_t depth) const
{
const peers_indexed::index<by_time>::type& by_time_index = m_peers_white.get<by_time>();
uint32_t cnt = 0;
BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index)
{
if (!vl.last_seen)
continue;
bs_head.push_back(vl);
if (cnt++ > depth)
break;
}
return true;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::get_peerlist_full(std::list<PeerlistEntry>& pl_gray, std::list<PeerlistEntry>& pl_white) const
{
const peers_indexed::index<by_time>::type& by_time_index_gr = m_peers_gray.get<by_time>();
const peers_indexed::index<by_time>::type& by_time_index_wt = m_peers_white.get<by_time>();
std::copy(by_time_index_gr.rbegin(), by_time_index_gr.rend(), std::back_inserter(pl_gray));
std::copy(by_time_index_wt.rbegin(), by_time_index_wt.rend(), std::back_inserter(pl_white));
return true;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::set_peer_just_seen(PeerIdType peer, uint32_t ip, uint32_t port)
{
NetworkAddress addr;
addr.ip = ip;
addr.port = port;
return set_peer_just_seen(peer, addr);
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::set_peer_just_seen(PeerIdType peer, const NetworkAddress& addr)
{
try {
//find in white list
PeerlistEntry ple;
ple.adr = addr;
ple.id = peer;
ple.last_seen = time(NULL);
return append_with_peer_white(ple);
} catch (std::exception&) {
}
return false;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::append_with_peer_white(const PeerlistEntry& ple)
{
try {
if (!is_ip_allowed(ple.adr.ip))
return true;
//find in white list
auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);
if (by_addr_it_wt == m_peers_white.get<by_addr>().end()) {
//put new record into white list
m_peers_white.insert(ple);
trim_white_peerlist();
} else {
//update record in white list
m_peers_white.replace(by_addr_it_wt, ple);
}
//remove from gray list, if need
auto by_addr_it_gr = m_peers_gray.get<by_addr>().find(ple.adr);
if (by_addr_it_gr != m_peers_gray.get<by_addr>().end()) {
m_peers_gray.erase(by_addr_it_gr);
}
return true;
} catch (std::exception&) {
}
return false;
}
//--------------------------------------------------------------------------------------------------
bool PeerlistManager::append_with_peer_gray(const PeerlistEntry& ple)
{
try {
if (!is_ip_allowed(ple.adr.ip))
return true;
//find in white list
auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);
if (by_addr_it_wt != m_peers_white.get<by_addr>().end())
return true;
//update gray list
auto by_addr_it_gr = m_peers_gray.get<by_addr>().find(ple.adr);
if (by_addr_it_gr == m_peers_gray.get<by_addr>().end())
{
//put new record into white list
m_peers_gray.insert(ple);
trim_gray_peerlist();
} else
{
//update record in white list
m_peers_gray.replace(by_addr_it_gr, ple);
}
return true;
} catch (std::exception&) {
}
return false;
}
//--------------------------------------------------------------------------------------------------
PeerlistManager::Peerlist& PeerlistManager::getWhite() {
return m_whitePeerlist;
}
PeerlistManager::Peerlist& PeerlistManager::getGray() {
return m_grayPeerlist;
}