AttemptToEvictConnection
This commit is contained in:
parent
4bac601610
commit
2c701537c8
110
src/net.cpp
110
src/net.cpp
@ -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());
|
||||
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;
|
||||
}
|
||||
|
||||
if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections)))
|
||||
{
|
||||
LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString());
|
||||
CloseSocket(hSocket);
|
||||
return;
|
||||
}
|
||||
|
||||
CNode* pnode = new CNode(hSocket, addr, "", true);
|
||||
|
Loading…
Reference in New Issue
Block a user