|
|
@ -776,6 +776,106 @@ void SocketSendData(CNode *pnode) |
|
|
|
|
|
|
|
|
|
|
|
static list<CNode*> vNodesDisconnected; |
|
|
|
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) { |
|
|
|
static void AcceptConnection(const ListenSocket& hListenSocket) { |
|
|
|
struct sockaddr_storage sockaddr; |
|
|
|
struct sockaddr_storage sockaddr; |
|
|
|
socklen_t len = sizeof(sockaddr); |
|
|
|
socklen_t len = sizeof(sockaddr); |
|
|
@ -820,16 +920,12 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { |
|
|
|
|
|
|
|
|
|
|
|
if (nInbound >= nMaxInbound) |
|
|
|
if (nInbound >= nMaxInbound) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); |
|
|
|
if (!AttemptToEvictConnection()) { |
|
|
|
CloseSocket(hSocket); |
|
|
|
// No connection to evict, disconnect the new connection
|
|
|
|
return; |
|
|
|
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); |
|
|
|
CNode* pnode = new CNode(hSocket, addr, "", true); |
|
|
|