Skip to content

Commit a1c4aaf

Browse files
Patrick StratemanFuzzbawls
authored andcommitted
AttemptToEvictConnection
1 parent aa7ce9b commit a1c4aaf

1 file changed

Lines changed: 106 additions & 3 deletions

File tree

src/net.cpp

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,106 @@ void CheckOffsetDisconnectedPeers(const CNetAddr& ip)
889889

890890
static std::list<CNode*> vNodesDisconnected;
891891

892+
static bool ReverseCompareNodeMinPingTime(CNode *a, CNode *b)
893+
{
894+
return a->nMinPingUsecTime > b->nMinPingUsecTime;
895+
}
896+
897+
static bool ReverseCompareNodeTimeConnected(CNode *a, CNode *b)
898+
{
899+
return a->nTimeConnected > b->nTimeConnected;
900+
}
901+
902+
class CompareNetGroupKeyed
903+
{
904+
std::vector<unsigned char> vchSecretKey;
905+
public:
906+
CompareNetGroupKeyed()
907+
{
908+
vchSecretKey.resize(32, 0);
909+
GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
910+
}
911+
912+
bool operator()(CNode *a, CNode *b)
913+
{
914+
std::vector<unsigned char> vchGroupA, vchGroupB;
915+
CSHA256 hashA, hashB;
916+
std::vector<unsigned char> vchA(32), vchB(32);
917+
918+
vchGroupA = a->addr.GetGroup();
919+
vchGroupB = b->addr.GetGroup();
920+
921+
hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
922+
hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
923+
924+
hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
925+
hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
926+
927+
hashA.Finalize(begin_ptr(vchA));
928+
hashB.Finalize(begin_ptr(vchB));
929+
930+
return vchA < vchB;
931+
}
932+
};
933+
934+
static bool AttemptToEvictConnection() {
935+
std::vector<CNode*> vEvictionCandidates;
936+
{
937+
LOCK(cs_vNodes);
938+
939+
for (CNode *node : vNodes) {
940+
if (node->fWhitelisted)
941+
continue;
942+
if (!node->fInbound)
943+
continue;
944+
if (node->fDisconnect)
945+
continue;
946+
if (node->addr.IsLocal())
947+
continue;
948+
vEvictionCandidates.push_back(node);
949+
}
950+
}
951+
952+
// Protect connections with certain characteristics
953+
static CompareNetGroupKeyed comparerNetGroupKeyed;
954+
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed);
955+
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
956+
957+
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
958+
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
959+
960+
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
961+
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(64, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
962+
963+
if (vEvictionCandidates.empty())
964+
return false;
965+
966+
// Identify CNetAddr with the most connections
967+
CNetAddr naMostConnections;
968+
unsigned int nMostConnections = 0;
969+
std::map<CNetAddr, std::vector<CNode*> > mapAddrCounts;
970+
for (CNode *node : vEvictionCandidates) {
971+
mapAddrCounts[node->addr].push_back(node);
972+
973+
if (mapAddrCounts[node->addr].size() > nMostConnections) {
974+
nMostConnections = mapAddrCounts[node->addr].size();
975+
naMostConnections = node->addr;
976+
}
977+
}
978+
979+
// Reduce to the CNetAddr with the most connections
980+
vEvictionCandidates = mapAddrCounts[naMostConnections];
981+
982+
if (vEvictionCandidates.size() <= 1)
983+
return false;
984+
985+
// Disconnect the most recent connection from the CNetAddr with the most connections
986+
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
987+
vEvictionCandidates[0]->fDisconnect = true;
988+
989+
return true;
990+
}
991+
892992
static void AcceptConnection(const ListenSocket& hListenSocket) {
893993
struct sockaddr_storage sockaddr;
894994
socklen_t len = sizeof(sockaddr);
@@ -928,9 +1028,12 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
9281028
}
9291029

9301030
if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) {
931-
LogPrint(BCLog::NET, "connection from %s dropped (full)\n", addr.ToString());
932-
CloseSocket(hSocket);
933-
return;
1031+
if (!AttemptToEvictConnection()) {
1032+
// No connection to evict, disconnect the new connection
1033+
LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n");
1034+
CloseSocket(hSocket);
1035+
return;
1036+
}
9341037
}
9351038

9361039
CNode* pnode = new CNode(hSocket, addr, "", true);

0 commit comments

Comments
 (0)