Skip to content

Commit a55716a

Browse files
committed
Merge #9319: Break addnode out from the outbound connection limits.
032ba3f RPC help documentation for addnode peerinfo. (Gregory Maxwell) 90f13e1 Add release notes for addnode changes. (Gregory Maxwell) 50bd12c Break addnode out from the outbound connection limits. (Gregory Maxwell)
2 parents f646275 + 032ba3f commit a55716a

File tree

7 files changed

+64
-13
lines changed

7 files changed

+64
-13
lines changed

doc/release-notes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ Removal of Priority Estimation
6262
major version. To prepare for this, the default for the rate limit of priority
6363
transactions (`-limitfreerelay`) has been set to `0` kB/minute.
6464

65+
P2P connection management
66+
--------------------------
67+
68+
- Peers manually added through the addnode option or addnode RPC now have their own
69+
limit of eight connections which does not compete with other inbound or outbound
70+
connection usage and is not subject to the maxconnections limitation.
71+
72+
- New connections to manually added peers are much faster.
73+
74+
6575
0.14.0 Change log
6676
=================
6777

src/init.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -871,11 +871,11 @@ bool AppInitParameterInteraction()
871871
nMaxConnections = std::max(nUserMaxConnections, 0);
872872

873873
// Trim requested connection counts, to fit into system limitations
874-
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
875-
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
874+
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0);
875+
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
876876
if (nFD < MIN_CORE_FILEDESCRIPTORS)
877877
return InitError(_("Not enough file descriptors available."));
878-
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
878+
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
879879

880880
if (nMaxConnections < nUserMaxConnections)
881881
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
@@ -1109,7 +1109,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
11091109
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
11101110
LogPrintf("Using data directory %s\n", GetDataDir().string());
11111111
LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
1112-
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
1112+
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
11131113

11141114
InitSignatureCache();
11151115

@@ -1566,6 +1566,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
15661566
connOptions.nRelevantServices = nRelevantServices;
15671567
connOptions.nMaxConnections = nMaxConnections;
15681568
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
1569+
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
15691570
connOptions.nMaxFeeler = 1;
15701571
connOptions.nBestHeight = chainActive.Height();
15711572
connOptions.uiInterface = &uiInterface;

src/net.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ void CNode::copyStats(CNodeStats &stats)
621621
X(nVersion);
622622
X(cleanSubVer);
623623
X(fInbound);
624+
X(fAddnode);
624625
X(nStartingHeight);
625626
X(nSendBytes);
626627
X(mapSendBytesPerMsgCmd);
@@ -1631,7 +1632,12 @@ void CConnman::ThreadOpenConnections()
16311632
{
16321633
LOCK(cs_vNodes);
16331634
BOOST_FOREACH(CNode* pnode, vNodes) {
1634-
if (!pnode->fInbound) {
1635+
if (!pnode->fInbound && !pnode->fAddnode) {
1636+
// Netgroups for inbound and addnode peers are not excluded because our goal here
1637+
// is to not use multiple of our limited outbound slots on a single netgroup
1638+
// but inbound and addnode peers do not use our outbound slots. Inbound peers
1639+
// also have the added issue that they're attacker controlled and could be used
1640+
// to prevent us from connecting to particular hosts if we used them here.
16351641
setConnected.insert(pnode->addr.GetGroup());
16361642
nOutbound++;
16371643
}
@@ -1776,27 +1782,35 @@ void CConnman::ThreadOpenAddedConnections()
17761782
vAddedNodes = mapMultiArgs.at("-addnode");
17771783
}
17781784

1779-
for (unsigned int i = 0; true; i++)
1785+
while (true)
17801786
{
1787+
CSemaphoreGrant grant(*semAddnode);
17811788
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
1789+
bool tried = false;
17821790
for (const AddedNodeInfo& info : vInfo) {
17831791
if (!info.fConnected) {
1784-
CSemaphoreGrant grant(*semOutbound);
1792+
if (!grant.TryAcquire()) {
1793+
// If we've used up our semaphore and need a new one, lets not wait here since while we are waiting
1794+
// the addednodeinfo state might change.
1795+
break;
1796+
}
17851797
// If strAddedNode is an IP/port, decode it immediately, so
17861798
// OpenNetworkConnection can detect existing connections to that IP/port.
1799+
tried = true;
17871800
CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort()));
1788-
OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false);
1801+
OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true);
17891802
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
17901803
return;
17911804
}
17921805
}
1793-
if (!interruptNet.sleep_for(std::chrono::minutes(2)))
1806+
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
1807+
if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)));
17941808
return;
17951809
}
17961810
}
17971811

17981812
// if successful, this moves the passed grant to the constructed node
1799-
bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
1813+
bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode)
18001814
{
18011815
//
18021816
// Initiate outbound network connection
@@ -1825,6 +1839,8 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
18251839
pnode->fOneShot = true;
18261840
if (fFeeler)
18271841
pnode->fFeeler = true;
1842+
if (fAddnode)
1843+
pnode->fAddnode = true;
18281844

18291845
return true;
18301846
}
@@ -2076,8 +2092,10 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
20762092
nSendBufferMaxSize = 0;
20772093
nReceiveFloodSize = 0;
20782094
semOutbound = NULL;
2095+
semAddnode = NULL;
20792096
nMaxConnections = 0;
20802097
nMaxOutbound = 0;
2098+
nMaxAddnode = 0;
20812099
nBestHeight = 0;
20822100
clientInterface = NULL;
20832101
flagInterruptMsgProc = false;
@@ -2099,6 +2117,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
20992117
nLocalServices = connOptions.nLocalServices;
21002118
nMaxConnections = connOptions.nMaxConnections;
21012119
nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections);
2120+
nMaxAddnode = connOptions.nMaxAddnode;
21022121
nMaxFeeler = connOptions.nMaxFeeler;
21032122

21042123
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
@@ -2151,6 +2170,10 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
21512170
// initialize semaphore
21522171
semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
21532172
}
2173+
if (semAddnode == NULL) {
2174+
// initialize semaphore
2175+
semAddnode = new CSemaphore(nMaxAddnode);
2176+
}
21542177

21552178
//
21562179
// Start threads
@@ -2227,6 +2250,10 @@ void CConnman::Stop()
22272250
if (threadSocketHandler.joinable())
22282251
threadSocketHandler.join();
22292252

2253+
if (semAddnode)
2254+
for (int i=0; i<nMaxAddnode; i++)
2255+
semOutbound->post();
2256+
22302257
if (fAddressesInitialized)
22312258
{
22322259
DumpData();
@@ -2254,6 +2281,8 @@ void CConnman::Stop()
22542281
vhListenSocket.clear();
22552282
delete semOutbound;
22562283
semOutbound = NULL;
2284+
delete semAddnode;
2285+
semAddnode = NULL;
22572286
}
22582287

22592288
void CConnman::DeleteNode(CNode* pnode)
@@ -2554,6 +2583,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
25542583
strSubVer = "";
25552584
fWhitelisted = false;
25562585
fOneShot = false;
2586+
fAddnode = false;
25572587
fClient = false; // set by version message
25582588
fFeeler = false;
25592589
fSuccessfullyConnected = false;

src/net.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
5858
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
5959
/** Maximum length of strSubVer in `version` message */
6060
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
61-
/** Maximum number of outgoing nodes */
61+
/** Maximum number of automatic outgoing nodes */
6262
static const int MAX_OUTBOUND_CONNECTIONS = 8;
63+
/** Maximum number of addnode outgoing nodes */
64+
static const int MAX_ADDNODE_CONNECTIONS = 8;
6365
/** -listen default */
6466
static const bool DEFAULT_LISTEN = true;
6567
/** -upnp default */
@@ -135,6 +137,7 @@ class CConnman
135137
ServiceFlags nRelevantServices = NODE_NONE;
136138
int nMaxConnections = 0;
137139
int nMaxOutbound = 0;
140+
int nMaxAddnode = 0;
138141
int nMaxFeeler = 0;
139142
int nBestHeight = 0;
140143
CClientUIInterface* uiInterface = nullptr;
@@ -151,7 +154,7 @@ class CConnman
151154
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
152155
bool GetNetworkActive() const { return fNetworkActive; };
153156
void SetNetworkActive(bool active);
154-
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
157+
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
155158
bool CheckIncomingNonce(uint64_t nonce);
156159

157160
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -414,8 +417,10 @@ class CConnman
414417
ServiceFlags nRelevantServices;
415418

416419
CSemaphore *semOutbound;
420+
CSemaphore *semAddnode;
417421
int nMaxConnections;
418422
int nMaxOutbound;
423+
int nMaxAddnode;
419424
int nMaxFeeler;
420425
std::atomic<int> nBestHeight;
421426
CClientUIInterface* clientInterface;
@@ -529,6 +534,7 @@ class CNodeStats
529534
int nVersion;
530535
std::string cleanSubVer;
531536
bool fInbound;
537+
bool fAddnode;
532538
int nStartingHeight;
533539
uint64_t nSendBytes;
534540
mapMsgCmdSize mapSendBytesPerMsgCmd;
@@ -626,6 +632,7 @@ class CNode
626632
bool fWhitelisted; // This peer can bypass DoS banning.
627633
bool fFeeler; // If true this node is being used as a short lived feeler.
628634
bool fOneShot;
635+
bool fAddnode;
629636
bool fClient;
630637
const bool fInbound;
631638
bool fSuccessfullyConnected;

src/net_processing.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2644,6 +2644,8 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
26442644
state.fShouldBan = false;
26452645
if (pto->fWhitelisted)
26462646
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
2647+
else if (pto->fAddnode)
2648+
LogPrintf("Warning: not punishing addnoded peer %s!\n", pto->addr.ToString());
26472649
else {
26482650
pto->fDisconnect = true;
26492651
if (pto->addr.IsLocal())

src/rpc/net.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
9292
" \"version\": v, (numeric) The peer version, such as 7001\n"
9393
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
9494
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
95+
" \"addnode\": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot\n"
9596
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
9697
" \"banscore\": n, (numeric) The ban score\n"
9798
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
@@ -152,6 +153,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
152153
// their ver message.
153154
obj.push_back(Pair("subver", stats.cleanSubVer));
154155
obj.push_back(Pair("inbound", stats.fInbound));
156+
obj.push_back(Pair("addnode", stats.fAddnode));
155157
obj.push_back(Pair("startingheight", stats.nStartingHeight));
156158
if (fStateStats) {
157159
obj.push_back(Pair("banscore", statestats.nMisbehavior));

src/sync.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ class CSemaphoreGrant
264264
grant.Release();
265265
grant.sem = sem;
266266
grant.fHaveGrant = fHaveGrant;
267-
sem = NULL;
268267
fHaveGrant = false;
269268
}
270269

0 commit comments

Comments
 (0)