aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Strateman <patrick.strateman@gmail.com>2015-08-13 02:58:58 -0700
committerPatrick Strateman <patrick.strateman@gmail.com>2015-08-22 15:38:24 -0700
commit2c701537c8fc7f4cfb0163ec1f49662120e61eb7 (patch)
tree8a214908600caeecd4d27ecd0ea9691e34bed0f7
parent4bac60161029de6d71ef1e51e7af803ce6fb8405 (diff)
AttemptToEvictConnection
-rw-r--r--src/net.cpp116
1 files changed, 106 insertions, 10 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 248aedfa12..0fab0f82af 100644
--- a/src/net.cpp
+++ b/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());
- 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);