AttemptToEvictConnection

This commit is contained in:
Patrick Strateman 2015-08-13 02:58:58 -07:00
parent 4bac601610
commit 2c701537c8

View file

@ -776,6 +776,106 @@ void SocketSendData(CNode *pnode)
static list<CNode*> vNodesDisconnected;
static bool ReverseCompareNodeMinPingTime(CNode *a, CNode *b)
{
return a->nMinPingUsecTime > b->nMinPingUsecTime;
}
static bool ReverseCompareNodeTimeConnected(CNode *a, CNode *b)
{
return a->nTimeConnected > b->nTimeConnected;
}
class CompareNetGroupKeyed
{
std::vector<unsigned char> vchSecretKey;
public:
CompareNetGroupKeyed()
{
vchSecretKey.resize(32, 0);
GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
}
bool operator()(CNode *a, CNode *b)
{
std::vector<unsigned char> vchGroupA, vchGroupB;
CSHA256 hashA, hashB;
std::vector<unsigned char> vchA(32), vchB(32);
vchGroupA = a->addr.GetGroup();
vchGroupB = b->addr.GetGroup();
hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
hashA.Finalize(begin_ptr(vchA));
hashB.Finalize(begin_ptr(vchB));
return vchA < vchB;
}
};
static bool AttemptToEvictConnection() {
std::vector<CNode*> vEvictionCandidates;
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode *node, vNodes) {
if (node->fWhitelisted)
continue;
if (!node->fInbound)
continue;
if (node->fDisconnect)
continue;
if (node->addr.IsLocal())
continue;
vEvictionCandidates.push_back(node);
}
}
// Protect connections with certain characteristics
static CompareNetGroupKeyed comparerNetGroupKeyed;
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed);
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(64, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
if (vEvictionCandidates.empty())
return false;
// Identify CNetAddr with the most connections
CNetAddr naMostConnections;
unsigned int nMostConnections = 0;
std::map<CNetAddr, std::vector<CNode*> > mapAddrCounts;
BOOST_FOREACH(CNode *node, vEvictionCandidates) {
mapAddrCounts[node->addr].push_back(node);
if (mapAddrCounts[node->addr].size() > nMostConnections) {
nMostConnections = mapAddrCounts[node->addr].size();
naMostConnections = node->addr;
}
}
// Reduce to the CNetAddr with the most connections
vEvictionCandidates = mapAddrCounts[naMostConnections];
if (vEvictionCandidates.size() <= 1)
return false;
// Disconnect the most recent connection from the CNetAddr with the most connections
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
vEvictionCandidates[0]->fDisconnect = true;
return true;
}
static void AcceptConnection(const ListenSocket& hListenSocket) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
@ -820,16 +920,12 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
if (nInbound >= nMaxInbound)
{
LogPrint("net", "connection from %s dropped (full)\n", addr.ToString());
CloseSocket(hSocket);
return;
}
if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections)))
{
LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString());
CloseSocket(hSocket);
return;
if (!AttemptToEvictConnection()) {
// No connection to evict, disconnect the new connection
LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
CloseSocket(hSocket);
return;
}
}
CNode* pnode = new CNode(hSocket, addr, "", true);