Skip to content

Commit 5027e93

Browse files
vasildfanquake
authored andcommitted
i2p: reuse created I2P sessions if not used
In the case of `i2pacceptincoming=0` we use transient addresses (destinations) for ourselves for each outbound connection. It may happen that we * create the session (and thus our address/destination too) * fail to connect to the particular peer (e.g. if they are offline) * dispose the unused session. This puts unnecessary load on the I2P network because session creation is not cheap. Is exaggerated if `onlynet=i2p` is used in which case we will be trying to connect to I2P peers more often. To help with this, save the created but unused sessions and pick them later instead of creating new ones. Alleviates: #26754 Github-Pull: #26837 Rebased-From: b906b64
1 parent a62c541 commit 5027e93

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

src/net.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ static CAddress GetBindAddress(const Sock& sock)
436436

437437
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type)
438438
{
439+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
439440
assert(conn_type != ConnectionType::INBOUND);
440441

441442
if (pszDest == nullptr) {
@@ -496,8 +497,23 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
496497
if (m_i2p_sam_session) {
497498
connected = m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed);
498499
} else {
499-
i2p_transient_session = std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
500+
{
501+
LOCK(m_unused_i2p_sessions_mutex);
502+
if (m_unused_i2p_sessions.empty()) {
503+
i2p_transient_session =
504+
std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
505+
} else {
506+
i2p_transient_session.swap(m_unused_i2p_sessions.front());
507+
m_unused_i2p_sessions.pop();
508+
}
509+
}
500510
connected = i2p_transient_session->Connect(addrConnect, conn, proxyConnectionFailed);
511+
if (!connected) {
512+
LOCK(m_unused_i2p_sessions_mutex);
513+
if (m_unused_i2p_sessions.size() < MAX_UNUSED_I2P_SESSIONS_SIZE) {
514+
m_unused_i2p_sessions.emplace(i2p_transient_session.release());
515+
}
516+
}
501517
}
502518

503519
if (connected) {
@@ -1048,6 +1064,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
10481064

10491065
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
10501066
{
1067+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
10511068
std::optional<int> max_connections;
10521069
switch (conn_type) {
10531070
case ConnectionType::INBOUND:
@@ -1510,6 +1527,7 @@ void CConnman::DumpAddresses()
15101527

15111528
void CConnman::ProcessAddrFetch()
15121529
{
1530+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
15131531
std::string strDest;
15141532
{
15151533
LOCK(m_addr_fetches_mutex);
@@ -1578,6 +1596,7 @@ int CConnman::GetExtraBlockRelayCount() const
15781596

15791597
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
15801598
{
1599+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
15811600
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
15821601
FastRandomContext rng;
15831602
// Connect to specific addresses
@@ -1929,6 +1948,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
19291948

19301949
void CConnman::ThreadOpenAddedConnections()
19311950
{
1951+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
19321952
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_ADD_CONNECTION);
19331953
while (true)
19341954
{
@@ -1958,6 +1978,7 @@ void CConnman::ThreadOpenAddedConnections()
19581978
// if successful, this moves the passed grant to the constructed node
19591979
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, ConnectionType conn_type)
19601980
{
1981+
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
19611982
assert(conn_type != ConnectionType::INBOUND);
19621983

19631984
//

src/net.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <map>
3939
#include <memory>
4040
#include <optional>
41+
#include <queue>
4142
#include <thread>
4243
#include <vector>
4344

@@ -744,7 +745,7 @@ class CConnman
744745
bool GetNetworkActive() const { return fNetworkActive; };
745746
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
746747
void SetNetworkActive(bool active);
747-
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
748+
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
748749
bool CheckIncomingNonce(uint64_t nonce);
749750

750751
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -820,7 +821,7 @@ class CConnman
820821
* - Max total outbound connection capacity filled
821822
* - Max connection capacity for type is filled
822823
*/
823-
bool AddConnection(const std::string& address, ConnectionType conn_type);
824+
bool AddConnection(const std::string& address, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
824825

825826
size_t GetNodeCount(ConnectionDirection) const;
826827
void GetNodeStats(std::vector<CNodeStats>& vstats) const;
@@ -886,10 +887,10 @@ class CConnman
886887
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
887888
bool InitBinds(const Options& options);
888889

889-
void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
890+
void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex);
890891
void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
891-
void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
892-
void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex);
892+
void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex);
893+
void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex);
893894
void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
894895
void ThreadI2PAcceptIncoming();
895896
void AcceptConnection(const ListenSocket& hListenSocket);
@@ -956,7 +957,7 @@ class CConnman
956957
bool AlreadyConnectedToAddress(const CAddress& addr);
957958

958959
bool AttemptToEvictConnection();
959-
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
960+
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
960961
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
961962

962963
void DeleteNode(CNode* pnode);
@@ -1127,6 +1128,26 @@ class CConnman
11271128
*/
11281129
std::vector<CService> m_onion_binds;
11291130

1131+
/**
1132+
* Mutex protecting m_i2p_sam_sessions.
1133+
*/
1134+
Mutex m_unused_i2p_sessions_mutex;
1135+
1136+
/**
1137+
* A pool of created I2P SAM transient sessions that should be used instead
1138+
* of creating new ones in order to reduce the load on the I2P network.
1139+
* Creating a session in I2P is not cheap, thus if this is not empty, then
1140+
* pick an entry from it instead of creating a new session. If connecting to
1141+
* a host fails, then the created session is put to this pool for reuse.
1142+
*/
1143+
std::queue<std::unique_ptr<i2p::sam::Session>> m_unused_i2p_sessions GUARDED_BY(m_unused_i2p_sessions_mutex);
1144+
1145+
/**
1146+
* Cap on the size of `m_unused_i2p_sessions`, to ensure it does not
1147+
* unexpectedly use too much memory.
1148+
*/
1149+
static constexpr size_t MAX_UNUSED_I2P_SESSIONS_SIZE{10};
1150+
11301151
/**
11311152
* RAII helper to atomically create a copy of `m_nodes` and add a reference
11321153
* to each of the nodes. The nodes are released when this object is destroyed.

0 commit comments

Comments
 (0)