diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 5ed330c8..4d00ad6f 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -59,6 +59,7 @@ namespace tunnel void TunnelPool::SetExplicitPeers (std::shared_ptr > explicitPeers) { + std::unique_lock l(m_ExplicitPeersMutex); m_ExplicitPeers = explicitPeers; if (m_ExplicitPeers) { @@ -92,6 +93,7 @@ namespace tunnel it->SetTunnelPool (nullptr); m_OutboundTunnels.clear (); } + std::unique_lock l(m_TestsMutex); m_Tests.clear (); } @@ -126,6 +128,7 @@ namespace tunnel } m_InboundTunnels.insert (createdTunnel); } + std::unique_lock l(m_LocalDestinationMutex); if (m_LocalDestination) m_LocalDestination->SetLeaseSetUpdated (); } @@ -135,10 +138,11 @@ namespace tunnel if (expiredTunnel) { expiredTunnel->SetTunnelPool (nullptr); + std::unique_lock lt(m_TestsMutex); for (auto& it: m_Tests) if (it.second.second == expiredTunnel) it.second.second = nullptr; - std::unique_lock l(m_InboundTunnelsMutex); + std::unique_lock li(m_InboundTunnelsMutex); m_InboundTunnels.erase (expiredTunnel); } } @@ -157,10 +161,11 @@ namespace tunnel if (expiredTunnel) { expiredTunnel->SetTunnelPool (nullptr); + std::unique_lock lt(m_TestsMutex); for (auto& it: m_Tests) if (it.second.first == expiredTunnel) it.second.first = nullptr; - std::unique_lock l(m_OutboundTunnelsMutex); + std::unique_lock lo(m_OutboundTunnelsMutex); m_OutboundTunnels.erase (expiredTunnel); } } @@ -261,11 +266,21 @@ namespace tunnel return tunnel; } + std::shared_ptr TunnelPool::GetLocalDestination () const { + std::unique_lock l(m_LocalDestinationMutex); + return m_LocalDestination; + } + + void TunnelPool::SetLocalDestination (std::shared_ptr destination) { + std::unique_lock l(m_LocalDestinationMutex); + m_LocalDestination = destination; + } + void TunnelPool::CreateTunnels () { int num = 0; { - std::unique_lock l(m_OutboundTunnelsMutex); + std::unique_lock lo(m_OutboundTunnelsMutex); for (const auto& it : m_OutboundTunnels) if (it->IsEstablished ()) num++; } @@ -274,10 +289,11 @@ namespace tunnel num = 0; { - std::unique_lock l(m_InboundTunnelsMutex); + std::unique_lock li(m_InboundTunnelsMutex); for (const auto& it : m_InboundTunnels) if (it->IsEstablished ()) num++; } + std::unique_lock lo(m_OutboundTunnelsMutex); if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0) { for (auto it: m_OutboundTunnels) @@ -287,9 +303,11 @@ namespace tunnel if (num >= m_NumInboundTunnels) break; } } + lo.unlock(); for (int i = num; i < m_NumInboundTunnels; i++) CreateInboundTunnel (); + std::unique_lock l(m_LocalDestinationMutex); if (num < m_NumInboundTunnels && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB m_LocalDestination->SetLeaseSetUpdated (); // update LeaseSet immediately } @@ -311,7 +329,7 @@ namespace tunnel if (it.second.first->GetState () == eTunnelStateTestFailed) { it.second.first->SetState (eTunnelStateFailed); - std::unique_lock l(m_OutboundTunnelsMutex); + std::unique_lock lo(m_OutboundTunnelsMutex); m_OutboundTunnels.erase (it.second.first); } else @@ -323,9 +341,10 @@ namespace tunnel { it.second.second->SetState (eTunnelStateFailed); { - std::unique_lock l(m_InboundTunnelsMutex); + std::unique_lock li(m_InboundTunnelsMutex); m_InboundTunnels.erase (it.second.second); } + std::unique_lock ld(m_LocalDestinationMutex); if (m_LocalDestination) m_LocalDestination->SetLeaseSetUpdated (); } @@ -335,7 +354,10 @@ namespace tunnel } // new tests + std::unique_lock lt(m_TestsMutex); + std::unique_lock lo(m_OutboundTunnelsMutex); auto it1 = m_OutboundTunnels.begin (); + std::unique_lock li(m_InboundTunnelsMutex); auto it2 = m_InboundTunnels.begin (); while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) { @@ -355,7 +377,6 @@ namespace tunnel uint32_t msgID; RAND_bytes ((uint8_t *)&msgID, 4); { - std::unique_lock l(m_TestsMutex); m_Tests[msgID] = std::make_pair (*it1, *it2); } (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), @@ -377,10 +398,11 @@ namespace tunnel void TunnelPool::ProcessGarlicMessage (std::shared_ptr msg) { + std::unique_lock l(m_LocalDestinationMutex); if (m_LocalDestination) m_LocalDestination->ProcessGarlicMessage (msg); else - LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped"); + LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, garlic message dropped"); } void TunnelPool::ProcessDeliveryStatus (std::shared_ptr msg) @@ -425,10 +447,11 @@ namespace tunnel } else { + std::unique_lock l(m_LocalDestinationMutex); if (m_LocalDestination) m_LocalDestination->ProcessDeliveryStatusMessage (msg); else - LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); + LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, delivery status message dropped"); } } @@ -512,13 +535,16 @@ namespace tunnel if (m_CustomPeerSelector) return m_CustomPeerSelector->SelectPeers(path, numHops, isInbound); } + // explicit peers in use + std::lock_guard lock(m_ExplicitPeersMutex); if (m_ExplicitPeers) return SelectExplicitPeers (path, isInbound); return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1, std::placeholders::_2)); } bool TunnelPool::SelectExplicitPeers (Path& path, bool isInbound) { + std::unique_lock l(m_ExplicitPeersMutex); int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size (); if (!numHops) return false; @@ -610,8 +636,10 @@ namespace tunnel Path path; if (SelectPeers (path, false)) { + std::unique_lock ld(m_LocalDestinationMutex); if (m_LocalDestination && !m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) path.isShort = false; // because can't handle ECIES encrypted reply + ld.unlock(); std::shared_ptr config; if (m_NumOutboundHops > 0) diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 875a9955..1069e1b9 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -64,8 +64,8 @@ namespace tunnel TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels); ~TunnelPool (); - std::shared_ptr GetLocalDestination () const { return m_LocalDestination; }; - void SetLocalDestination (std::shared_ptr destination) { m_LocalDestination = destination; }; + std::shared_ptr GetLocalDestination () const; + void SetLocalDestination (std::shared_ptr destination); void SetExplicitPeers (std::shared_ptr > explicitPeers); void CreateTunnels (); @@ -126,8 +126,10 @@ namespace tunnel private: + mutable std::mutex m_LocalDestinationMutex; std::shared_ptr m_LocalDestination; int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels; + mutable std::mutex m_ExplicitPeersMutex; std::shared_ptr > m_ExplicitPeers; mutable std::mutex m_InboundTunnelsMutex; std::set, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first