Skip to content

Commit 3f89a53

Browse files
committed
Merge #8113: Rework addnode behaviour
1a5a4e6 Randomize name lookup result in ConnectSocketByName (Pieter Wuille) f9f5cfc Prevent duplicate connections where one is by name and another by ip (Pieter Wuille) 1111b80 Rework addnode behaviour (Pieter Wuille)
2 parents 62fcf27 + 1a5a4e6 commit 3f89a53

File tree

4 files changed

+115
-125
lines changed

4 files changed

+115
-125
lines changed

src/net.cpp

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,26 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
400400
return NULL;
401401
}
402402

403+
if (pszDest && addrConnect.IsValid()) {
404+
// It is possible that we already have a connection to the IP/port pszDest resolved to.
405+
// In that case, drop the connection that was just created, and return the existing CNode instead.
406+
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
407+
// name catch this early.
408+
CNode* pnode = FindNode((CService)addrConnect);
409+
if (pnode)
410+
{
411+
pnode->AddRef();
412+
{
413+
LOCK(cs_vNodes);
414+
if (pnode->addrName.empty()) {
415+
pnode->addrName = std::string(pszDest);
416+
}
417+
}
418+
CloseSocket(hSocket);
419+
return pnode;
420+
}
421+
}
422+
403423
addrman.Attempt(addrConnect, fCountFailure);
404424

405425
// Add node
@@ -1659,68 +1679,79 @@ void ThreadOpenConnections()
16591679
}
16601680
}
16611681

1662-
void ThreadOpenAddedConnections()
1682+
std::vector<AddedNodeInfo> GetAddedNodeInfo()
16631683
{
1684+
std::vector<AddedNodeInfo> ret;
1685+
1686+
std::list<std::string> lAddresses(0);
16641687
{
16651688
LOCK(cs_vAddedNodes);
1666-
vAddedNodes = mapMultiArgs["-addnode"];
1689+
ret.reserve(vAddedNodes.size());
1690+
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1691+
lAddresses.push_back(strAddNode);
16671692
}
16681693

1669-
if (HaveNameProxy()) {
1670-
while(true) {
1671-
std::list<std::string> lAddresses(0);
1672-
{
1673-
LOCK(cs_vAddedNodes);
1674-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1675-
lAddresses.push_back(strAddNode);
1694+
1695+
// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
1696+
std::map<CService, bool> mapConnected;
1697+
std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
1698+
{
1699+
LOCK(cs_vNodes);
1700+
for (const CNode* pnode : vNodes) {
1701+
if (pnode->addr.IsValid()) {
1702+
mapConnected[pnode->addr] = pnode->fInbound;
16761703
}
1677-
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1678-
CAddress addr;
1679-
CSemaphoreGrant grant(*semOutbound);
1680-
OpenNetworkConnection(addr, false, &grant, strAddNode.c_str());
1681-
MilliSleep(500);
1704+
if (!pnode->addrName.empty()) {
1705+
mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));
1706+
}
1707+
}
1708+
}
1709+
1710+
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1711+
CService service(strAddNode, Params().GetDefaultPort());
1712+
if (service.IsValid()) {
1713+
// strAddNode is an IP:port
1714+
auto it = mapConnected.find(service);
1715+
if (it != mapConnected.end()) {
1716+
ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});
1717+
} else {
1718+
ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
1719+
}
1720+
} else {
1721+
// strAddNode is a name
1722+
auto it = mapConnectedByName.find(strAddNode);
1723+
if (it != mapConnectedByName.end()) {
1724+
ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});
1725+
} else {
1726+
ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
16821727
}
1683-
MilliSleep(120000); // Retry every 2 minutes
16841728
}
16851729
}
16861730

1731+
return ret;
1732+
}
1733+
1734+
void ThreadOpenAddedConnections()
1735+
{
1736+
{
1737+
LOCK(cs_vAddedNodes);
1738+
vAddedNodes = mapMultiArgs["-addnode"];
1739+
}
1740+
16871741
for (unsigned int i = 0; true; i++)
16881742
{
1689-
std::list<std::string> lAddresses(0);
1690-
{
1691-
LOCK(cs_vAddedNodes);
1692-
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
1693-
lAddresses.push_back(strAddNode);
1743+
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
1744+
for (const AddedNodeInfo& info : vInfo) {
1745+
if (!info.fConnected) {
1746+
CSemaphoreGrant grant(*semOutbound);
1747+
// If strAddedNode is an IP/port, decode it immediately, so
1748+
// OpenNetworkConnection can detect existing connections to that IP/port.
1749+
CService service(info.strAddedNode, Params().GetDefaultPort());
1750+
OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false);
1751+
MilliSleep(500);
1752+
}
16941753
}
16951754

1696-
std::list<std::vector<CService> > lservAddressesToAdd(0);
1697-
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
1698-
std::vector<CService> vservNode(0);
1699-
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
1700-
lservAddressesToAdd.push_back(vservNode);
1701-
}
1702-
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1703-
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
1704-
{
1705-
LOCK(cs_vNodes);
1706-
BOOST_FOREACH(CNode* pnode, vNodes)
1707-
for (std::list<std::vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1708-
BOOST_FOREACH(const CService& addrNode, *(it))
1709-
if (pnode->addr == addrNode)
1710-
{
1711-
it = lservAddressesToAdd.erase(it);
1712-
it--;
1713-
break;
1714-
}
1715-
}
1716-
BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
1717-
{
1718-
CSemaphoreGrant grant(*semOutbound);
1719-
/* We want -addnode to work even for nodes that don't provide all
1720-
* wanted services, so pass in nServices=NODE_NONE to CAddress. */
1721-
OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant);
1722-
MilliSleep(500);
1723-
}
17241755
MilliSleep(120000); // Retry every 2 minutes
17251756
}
17261757
}

src/net.h

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

826+
struct AddedNodeInfo
827+
{
828+
std::string strAddedNode;
829+
CService resolvedAddress;
830+
bool fConnected;
831+
bool fInbound;
832+
};
833+
834+
std::vector<AddedNodeInfo> GetAddedNodeInfo();
835+
826836
#endif // BITCOIN_NET_H

src/netbase.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -621,10 +621,10 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
621621
proxyType nameProxy;
622622
GetNameProxy(nameProxy);
623623

624-
CService addrResolved;
625-
if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy())) {
626-
if (addrResolved.IsValid()) {
627-
addr = addrResolved;
624+
std::vector<CService> addrResolved;
625+
if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
626+
if (addrResolved.size() > 0) {
627+
addr = addrResolved[GetRand(addrResolved.size())];
628628
return ConnectSocket(addr, hSocketRet, nTimeout);
629629
}
630630
}

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)