Skip to content

Commit 1111b80

Browse files
committed
Rework addnode behaviour
* Use CNode::addeName to track whether a connection to a name is already open * A new connection to a previously-connected by-name addednode is only opened when the previous one closes (even if the name starts resolving to something else) * At most one connection is opened per addednode (even if the name resolves to multiple) * Unify the code between ThreadOpenAddedNodeConnections and getaddednodeinfo * Information about open connections is always returned, and the dns argument becomes a dummy * An IP address and inbound/outbound is only reported for the (at most 1) open connection
1 parent be9711e commit 1111b80

File tree

3 files changed

+91
-121
lines changed

3 files changed

+91
-121
lines changed

src/net.cpp

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,68 +1616,79 @@ void ThreadOpenConnections()
16161616
}
16171617
}
16181618

1619-
void ThreadOpenAddedConnections()
1619+
std::vector<AddedNodeInfo> GetAddedNodeInfo()
16201620
{
1621+
std::vector<AddedNodeInfo> ret;
1622+
1623+
std::list<std::string> lAddresses(0);
16211624
{
16221625
LOCK(cs_vAddedNodes);
1623-
vAddedNodes = mapMultiArgs["-addnode"];
1626+
ret.reserve(vAddedNodes.size());
1627+
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1628+
lAddresses.push_back(strAddNode);
16241629
}
16251630

1626-
if (HaveNameProxy()) {
1627-
while(true) {
1628-
std::list<std::string> lAddresses(0);
1629-
{
1630-
LOCK(cs_vAddedNodes);
1631-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1632-
lAddresses.push_back(strAddNode);
1631+
1632+
// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
1633+
std::map<CService, bool> mapConnected;
1634+
std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
1635+
{
1636+
LOCK(cs_vNodes);
1637+
for (const CNode* pnode : vNodes) {
1638+
if (pnode->addr.IsValid()) {
1639+
mapConnected[pnode->addr] = pnode->fInbound;
16331640
}
1634-
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1635-
CAddress addr;
1636-
CSemaphoreGrant grant(*semOutbound);
1637-
OpenNetworkConnection(addr, false, &grant, strAddNode.c_str());
1638-
MilliSleep(500);
1641+
if (!pnode->addrName.empty()) {
1642+
mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));
16391643
}
1640-
MilliSleep(120000); // Retry every 2 minutes
16411644
}
16421645
}
16431646

1647+
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1648+
CService service(strAddNode, Params().GetDefaultPort());
1649+
if (service.IsValid()) {
1650+
// strAddNode is an IP:port
1651+
auto it = mapConnected.find(service);
1652+
if (it != mapConnected.end()) {
1653+
ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});
1654+
} else {
1655+
ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
1656+
}
1657+
} else {
1658+
// strAddNode is a name
1659+
auto it = mapConnectedByName.find(strAddNode);
1660+
if (it != mapConnectedByName.end()) {
1661+
ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});
1662+
} else {
1663+
ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
1664+
}
1665+
}
1666+
}
1667+
1668+
return ret;
1669+
}
1670+
1671+
void ThreadOpenAddedConnections()
1672+
{
1673+
{
1674+
LOCK(cs_vAddedNodes);
1675+
vAddedNodes = mapMultiArgs["-addnode"];
1676+
}
1677+
16441678
for (unsigned int i = 0; true; i++)
16451679
{
1646-
std::list<std::string> lAddresses(0);
1647-
{
1648-
LOCK(cs_vAddedNodes);
1649-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1650-
lAddresses.push_back(strAddNode);
1680+
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
1681+
for (const AddedNodeInfo& info : vInfo) {
1682+
if (!info.fConnected) {
1683+
CSemaphoreGrant grant(*semOutbound);
1684+
// If strAddedNode is an IP/port, decode it immediately, so
1685+
// OpenNetworkConnection can detect existing connections to that IP/port.
1686+
CService service(info.strAddedNode, Params().GetDefaultPort());
1687+
OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false);
1688+
MilliSleep(500);
1689+
}
16511690
}
16521691

1653-
std::list<std::vector<CService> > lservAddressesToAdd(0);
1654-
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1655-
std::vector<CService> vservNode(0);
1656-
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
1657-
lservAddressesToAdd.push_back(vservNode);
1658-
}
1659-
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1660-
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
1661-
{
1662-
LOCK(cs_vNodes);
1663-
BOOST_FOREACH(CNode* pnode, vNodes)
1664-
for (std::list<std::vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1665-
BOOST_FOREACH(const CService& addrNode, *(it))
1666-
if (pnode->addr == addrNode)
1667-
{
1668-
it = lservAddressesToAdd.erase(it);
1669-
it--;
1670-
break;
1671-
}
1672-
}
1673-
BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
1674-
{
1675-
CSemaphoreGrant grant(*semOutbound);
1676-
/* We want -addnode to work even for nodes that don't provide all
1677-
* wanted services, so pass in nServices=NODE_NONE to CAddress. */
1678-
OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant);
1679-
MilliSleep(500);
1680-
}
16811692
MilliSleep(120000); // Retry every 2 minutes
16821693
}
16831694
}

src/net.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,4 +818,14 @@ class CBanDB
818818
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
819819
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
820820

821+
struct AddedNodeInfo
822+
{
823+
std::string strAddedNode;
824+
CService resolvedAddress;
825+
bool fConnected;
826+
bool fInbound;
827+
};
828+
829+
std::vector<AddedNodeInfo> GetAddedNodeInfo();
830+
821831
#endif // BITCOIN_NET_H

src/rpc/net.cpp

Lines changed: 22 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -271,25 +271,22 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
271271
{
272272
if (fHelp || params.size() < 1 || params.size() > 2)
273273
throw runtime_error(
274-
"getaddednodeinfo dns ( \"node\" )\n"
274+
"getaddednodeinfo dummy ( \"node\" )\n"
275275
"\nReturns information about the given added node, or all added nodes\n"
276276
"(note that onetry addnodes are not listed here)\n"
277-
"If dns is false, only a list of added nodes will be provided,\n"
278-
"otherwise connected information will also be available.\n"
279277
"\nArguments:\n"
280-
"1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available.\n"
278+
"1. dummy (boolean, required) Kept for historical purposes but ignored\n"
281279
"2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
282280
"\nResult:\n"
283281
"[\n"
284282
" {\n"
285-
" \"addednode\" : \"192.168.0.201\", (string) The node ip address\n"
283+
" \"addednode\" : \"192.168.0.201\", (string) The node ip address or name (as provided to addnode)\n"
286284
" \"connected\" : true|false, (boolean) If connected\n"
287-
" \"addresses\" : [\n"
285+
" \"addresses\" : [ (list of objects) Only when connected = true\n"
288286
" {\n"
289-
" \"address\" : \"192.168.0.201:8333\", (string) The bitcoin server host and port\n"
287+
" \"address\" : \"192.168.0.201:8333\", (string) The bitcoin server IP and port we're connected to\n"
290288
" \"connected\" : \"outbound\" (string) connection, inbound or outbound\n"
291289
" }\n"
292-
" ,...\n"
293290
" ]\n"
294291
" }\n"
295292
" ,...\n"
@@ -300,83 +297,35 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
300297
+ HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
301298
);
302299

303-
bool fDns = params[0].get_bool();
300+
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
304301

305-
list<string> laddedNodes(0);
306-
if (params.size() == 1)
307-
{
308-
LOCK(cs_vAddedNodes);
309-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
310-
laddedNodes.push_back(strAddNode);
311-
}
312-
else
313-
{
314-
string strNode = params[1].get_str();
315-
LOCK(cs_vAddedNodes);
316-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) {
317-
if (strAddNode == strNode)
318-
{
319-
laddedNodes.push_back(strAddNode);
302+
if (params.size() == 2) {
303+
bool found = false;
304+
for (const AddedNodeInfo& info : vInfo) {
305+
if (info.strAddedNode == params[1].get_str()) {
306+
vInfo.assign(1, info);
307+
found = true;
320308
break;
321309
}
322310
}
323-
if (laddedNodes.size() == 0)
311+
if (!found) {
324312
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
325-
}
326-
327-
UniValue ret(UniValue::VARR);
328-
if (!fDns)
329-
{
330-
BOOST_FOREACH (const std::string& strAddNode, laddedNodes) {
331-
UniValue obj(UniValue::VOBJ);
332-
obj.push_back(Pair("addednode", strAddNode));
333-
ret.push_back(obj);
334313
}
335-
return ret;
336314
}
337315

338-
list<pair<string, vector<CService> > > laddedAddreses(0);
339-
BOOST_FOREACH(const std::string& strAddNode, laddedNodes) {
340-
vector<CService> vservNode(0);
341-
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
342-
laddedAddreses.push_back(make_pair(strAddNode, vservNode));
343-
else
344-
{
345-
UniValue obj(UniValue::VOBJ);
346-
obj.push_back(Pair("addednode", strAddNode));
347-
obj.push_back(Pair("connected", false));
348-
UniValue addresses(UniValue::VARR);
349-
obj.push_back(Pair("addresses", addresses));
350-
ret.push_back(obj);
351-
}
352-
}
316+
UniValue ret(UniValue::VARR);
353317

354-
LOCK(cs_vNodes);
355-
for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
356-
{
318+
for (const AddedNodeInfo& info : vInfo) {
357319
UniValue obj(UniValue::VOBJ);
358-
obj.push_back(Pair("addednode", it->first));
359-
320+
obj.push_back(Pair("addednode", info.strAddedNode));
321+
obj.push_back(Pair("connected", info.fConnected));
360322
UniValue addresses(UniValue::VARR);
361-
bool fConnected = false;
362-
BOOST_FOREACH(const CService& addrNode, it->second) {
363-
bool fFound = false;
364-
UniValue node(UniValue::VOBJ);
365-
node.push_back(Pair("address", addrNode.ToString()));
366-
BOOST_FOREACH(CNode* pnode, vNodes) {
367-
if (pnode->addr == addrNode)
368-
{
369-
fFound = true;
370-
fConnected = true;
371-
node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
372-
break;
373-
}
374-
}
375-
if (!fFound)
376-
node.push_back(Pair("connected", "false"));
377-
addresses.push_back(node);
323+
if (info.fConnected) {
324+
UniValue address(UniValue::VOBJ);
325+
address.push_back(Pair("address", info.resolvedAddress.ToString()));
326+
address.push_back(Pair("connected", info.fInbound ? "inbound" : "outbound"));
327+
addresses.push_back(address);
378328
}
379-
obj.push_back(Pair("connected", fConnected));
380329
obj.push_back(Pair("addresses", addresses));
381330
ret.push_back(obj);
382331
}

0 commit comments

Comments
 (0)