@@ -889,6 +889,106 @@ void CheckOffsetDisconnectedPeers(const CNetAddr& ip)
889889
890890static 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+
892992static 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