From 2a4450ccbbe30f6522c3108f136b2b867b2a87fe Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 22 Apr 2025 15:17:36 +0200 Subject: [PATCH] net: change FindNode() to not return a node and rename it All callers of `CConnman::FindNode()` use its return value `CNode*` only as a boolean null/notnull. So change that method to return `bool`. This removes the dangerous pattern of handling a `CNode` object (the return value of `FindNode()`) without holding `CConnman::m_nodes_mutex` and without having that object's reference count incremented for the duration of the usage. Also rename the method to better describe what it does. --- src/net.cpp | 31 +++++++++---------------------- src/net.h | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 6e95d6a3736..e0b5107fcff 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -331,26 +331,16 @@ bool IsLocal(const CService& addr) return mapLocalHost.count(addr) > 0; } -CNode* CConnman::FindNode(const std::string& addrName) +bool CConnman::AlreadyConnectedToHost(const std::string& host) const { LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (pnode->m_addr_name == addrName) { - return pnode; - } - } - return nullptr; + return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; }); } -CNode* CConnman::FindNode(const CService& addr) +bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const { LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (static_cast(pnode->addr) == addr) { - return pnode; - } - } - return nullptr; + return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; }); } bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const @@ -393,10 +383,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return nullptr; // Look for an existing connection - CNode* pnode = FindNode(static_cast(addrConnect)); - if (pnode) - { - LogPrintf("Failed to open new connection, already connected\n"); + if (AlreadyConnectedToAddressPort(addrConnect)) { + LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort()); return nullptr; } } @@ -426,9 +414,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo } // It is possible that we already have a connection to the IP/port pszDest resolved to. // In that case, drop the connection that was just created. - LOCK(m_nodes_mutex); - CNode* pnode = FindNode(static_cast(addrConnect)); - if (pnode) { + if (AlreadyConnectedToAddressPort(addrConnect)) { LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort()); return nullptr; } @@ -2996,8 +2982,9 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) { return; } - } else if (FindNode(std::string(pszDest))) + } else if (AlreadyConnectedToHost(pszDest)) { return; + } CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport); diff --git a/src/net.h b/src/net.h index 52044fe1eab..44730419815 100644 --- a/src/net.h +++ b/src/net.h @@ -1365,8 +1365,23 @@ private: uint64_t CalculateKeyedNetGroup(const CNetAddr& ad) const; - CNode* FindNode(const std::string& addrName); - CNode* FindNode(const CService& addr); + /** + * Determine whether we're already connected to a given "host:port". + * Note that for inbound connections, the peer is likely using a random outbound + * port on their side, so this will likely not match any inbound connections. + * @param[in] host String of the form "host[:port]", e.g. "localhost" or "localhost:8333" or "1.2.3.4:8333". + * @return true if connected to `host`. + */ + bool AlreadyConnectedToHost(const std::string& host) const; + + /** + * Determine whether we're already connected to a given address:port. + * Note that for inbound connections, the peer is likely using a random outbound + * port on their side, so this will likely not match any inbound connections. + * @param[in] addr_port Address and port to check. + * @return true if connected to addr_port. + */ + bool AlreadyConnectedToAddressPort(const CService& addr_port) const; /** * Determine whether we're already connected to a given address.