Added -whiteconnections=<n> option

This sets aside a number of connection slots for whitelisted peers,
useful for ensuring your local users and miners can always get in,
even if your limit on inbound connections has already been reached.
This commit is contained in:
Josh Lehan 2014-11-16 03:19:23 -08:00
parent ab0ec67903
commit e3cae52538
3 changed files with 68 additions and 11 deletions

View file

@ -328,6 +328,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway")); " " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
strUsage += HelpMessageOpt("-whiteconnections=<n>", strprintf(_("Reserve this many inbound connections for whitelisted peers (default: %d)"), 0));
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageGroup(_("Wallet options:"));
@ -723,16 +724,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__); LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
} }
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
nMaxConnections = GetArg("-maxconnections", 125);
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
// if using block pruning, then disable txindex // if using block pruning, then disable txindex
if (GetArg("-prune", 0)) { if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false)) if (GetBoolArg("-txindex", false))
@ -743,6 +734,47 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
#endif #endif
} }
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
int nUserMaxConnections = GetArg("-maxconnections", 125);
nMaxConnections = std::max(nUserMaxConnections, 0);
int nUserWhiteConnections = GetArg("-whiteconnections", 0);
nWhiteConnections = std::max(nUserWhiteConnections, 0);
if ((mapArgs.count("-whitelist")) || (mapArgs.count("-whitebind"))) {
if (!(mapArgs.count("-maxconnections"))) {
// User is using whitelist feature,
// but did not specify -maxconnections parameter.
// Silently increase the default to compensate,
// so that the whitelist connection reservation feature
// does not inadvertently reduce the default
// inbound connection capacity of the network.
nMaxConnections += nWhiteConnections;
}
} else {
// User not using whitelist feature.
// Silently disable connection reservation,
// for the same reason as above.
nWhiteConnections = 0;
}
// Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
if (nMaxConnections < nUserMaxConnections)
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// Connection capacity is prioritized in this order:
// outbound connections (hardcoded to 8),
// then whitelisted connections,
// then non-whitelisted connections get whatever's left (if any).
if ((nWhiteConnections > 0) && (nWhiteConnections >= (nMaxConnections - 8)))
InitWarning(strprintf(_("All non-whitelisted incoming connections will be dropped, because -whiteconnections is %d and -maxconnections is only %d."), nWhiteConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags // ********************************************************* Step 3: parameter-to-internal-flags
@ -910,6 +942,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Using data directory %s\n", strDataDir); LogPrintf("Using data directory %s\n", strDataDir);
LogPrintf("Using config file %s\n", GetConfigFile().string()); LogPrintf("Using config file %s\n", GetConfigFile().string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
if (nWhiteConnections > 0)
LogPrintf("Reserving %i of these connections for whitelisted inbound peers\n", nWhiteConnections);
std::ostringstream strErrors; std::ostringstream strErrors;
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);

View file

@ -79,6 +79,7 @@ uint64_t nLocalHostNonce = 0;
static std::vector<ListenSocket> vhListenSocket; static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman; CAddrMan addrman;
int nMaxConnections = 125; int nMaxConnections = 125;
int nWhiteConnections = 0;
bool fAddressesInitialized = false; bool fAddressesInitialized = false;
vector<CNode*> vNodes; vector<CNode*> vNodes;
@ -827,6 +828,7 @@ void ThreadSocketHandler()
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr; CAddress addr;
int nInbound = 0; int nInbound = 0;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
if (hSocket != INVALID_SOCKET) if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@ -846,8 +848,14 @@ void ThreadSocketHandler()
if (nErr != WSAEWOULDBLOCK) if (nErr != WSAEWOULDBLOCK)
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
} }
else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) else if (nInbound >= nMaxInbound)
{ {
LogPrint("net", "connection from %s dropped (full)\n", addr.ToString());
CloseSocket(hSocket);
}
else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections)))
{
LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString());
CloseSocket(hSocket); CloseSocket(hSocket);
} }
else if (CNode::IsBanned(addr) && !whitelisted) else if (CNode::IsBanned(addr) && !whitelisted)
@ -861,6 +869,8 @@ void ThreadSocketHandler()
pnode->AddRef(); pnode->AddRef();
pnode->fWhitelisted = whitelisted; pnode->fWhitelisted = whitelisted;
LogPrint("net", "connection from %s accepted\n", addr.ToString());
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
vNodes.push_back(pnode); vNodes.push_back(pnode);

View file

@ -140,7 +140,20 @@ extern bool fListen;
extern uint64_t nLocalServices; extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce; extern uint64_t nLocalHostNonce;
extern CAddrMan addrman; extern CAddrMan addrman;
// The allocation of connections against the maximum allowed (nMaxConnections)
// is prioritized as follows:
// 1st: Outbound connections (MAX_OUTBOUND_CONNECTIONS)
// 2nd: Inbound connections from whitelisted peers (nWhiteConnections)
// 3rd: Inbound connections from non-whitelisted peers
// Thus, the number of connection slots for the general public to use is:
// nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + nWhiteConnections)
// Any additional inbound connections beyond limits will be immediately closed
/** Maximum number of connections to simultaneously allow (aka connection slots) */
extern int nMaxConnections; extern int nMaxConnections;
/** Number of connection slots to reserve for inbound from whitelisted peers */
extern int nWhiteConnections;
extern std::vector<CNode*> vNodes; extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes; extern CCriticalSection cs_vNodes;