diff --git a/Destination.cpp b/Destination.cpp index 606bd619..63c89fff 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -24,6 +24,7 @@ namespace client int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY; int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; + std::shared_ptr > explicitPeers; if (params) { auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); @@ -66,8 +67,24 @@ namespace client LogPrint (eLogInfo, "Outbound tunnels quantity set to ", quantity); } } + it = params->find (I2CP_PARAM_EXPLICIT_PEERS); + if (it != params->end ()) + { + explicitPeers = std::make_shared >(); + std::stringstream ss(it->second); + std::string b64; + while (std::getline (ss, b64, ',')) + { + i2p::data::IdentHash ident; + ident.FromBase64 (b64); + explicitPeers->push_back (ident); + } + LogPrint (eLogInfo, "Explicit peers set to ", it->second); + } } m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity); + if (explicitPeers) + m_Pool->SetExplicitPeers (explicitPeers); if (m_IsPublic) LogPrint (eLogInfo, "Local address ", i2p::client::GetB32Address(GetIdentHash()), " created"); m_StreamingDestination = std::make_shared (*this); // TODO: diff --git a/Destination.h b/Destination.h index bf2dfcca..1f48ded0 100644 --- a/Destination.h +++ b/Destination.h @@ -40,6 +40,7 @@ namespace client const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5; const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity"; const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5; + const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers"; const int STREAM_REQUEST_TIMEOUT = 60; //in seconds typedef std::function stream)> StreamRequestComplete; diff --git a/Identity.h b/Identity.h index 02752d99..632c414a 100644 --- a/Identity.h +++ b/Identity.h @@ -69,6 +69,11 @@ namespace data i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); } + void FromBase64 (const std::string& s) + { + i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + private: union // 8 bytes alignment diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 0eaed3a3..478d6f11 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -1,3 +1,4 @@ +#include #include "I2PEndian.h" #include "CryptoConst.h" #include "Tunnel.h" @@ -22,6 +23,27 @@ namespace tunnel DetachTunnels (); } + void TunnelPool::SetExplicitPeers (std::shared_ptr > explicitPeers) + { + m_ExplicitPeers = explicitPeers; + if (m_ExplicitPeers) + { + int size = m_ExplicitPeers->size (); + if (m_NumInboundHops > size) + { + m_NumInboundHops = size; + LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers"); + } + if (m_NumOutboundHops > size) + { + m_NumOutboundHops = size; + LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers"); + } + m_NumInboundTunnels = 1; + m_NumOutboundTunnels = 1; + } + } + void TunnelPool::DetachTunnels () { { @@ -291,10 +313,11 @@ namespace tunnel return hop; } - bool TunnelPool::SelectPeers (std::vector >& hops) + bool TunnelPool::SelectPeers (std::vector >& hops, bool isInbound) { + if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound); auto prevHop = i2p::context.GetSharedRouterInfo (); - int numHops = m_NumInboundHops; + int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; if (i2p::transport::transports.GetNumPeers () > 25) { auto r = i2p::transport::transports.GetRandomPeer (); @@ -319,7 +342,31 @@ namespace tunnel } return true; } - + + bool TunnelPool::SelectExplicitPeers (std::vector >& hops, bool isInbound) + { + int size = m_ExplicitPeers->size (); + std::vector peerIndicies; + for (int i = 0; i < size; i++) peerIndicies.push_back(i); + std::random_shuffle (peerIndicies.begin(), peerIndicies.end()); + + int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; + for (int i = 0; i < numHops; i++) + { + auto& ident = (*m_ExplicitPeers)[peerIndicies[i]]; + auto r = i2p::data::netdb.FindRouter (ident); + if (r) + hops.push_back (r); + else + { + LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ()); + i2p::data::netdb.RequestDestination (ident); + return false; + } + } + return true; + } + void TunnelPool::CreateInboundTunnel () { auto outboundTunnel = GetNextOutboundTunnel (); @@ -327,7 +374,7 @@ namespace tunnel outboundTunnel = tunnels.GetNextOutboundTunnel (); LogPrint ("Creating destination inbound tunnel..."); std::vector > hops; - if (SelectPeers (hops)) + if (SelectPeers (hops, true)) { std::reverse (hops.begin (), hops.end ()); auto tunnel = tunnels.CreateTunnel (std::make_shared (hops), outboundTunnel); @@ -356,7 +403,7 @@ namespace tunnel { LogPrint ("Creating destination outbound tunnel..."); std::vector > hops; - if (SelectPeers (hops)) + if (SelectPeers (hops, false)) { auto tunnel = tunnels.CreateTunnel ( std::make_shared (hops, inboundTunnel->GetTunnelConfig ())); diff --git a/TunnelPool.h b/TunnelPool.h index b20cfaf2..2232a787 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -32,6 +32,7 @@ namespace tunnel i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; }; void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; }; + void SetExplicitPeers (std::shared_ptr > explicitPeers); void CreateTunnels (); void TunnelCreated (std::shared_ptr createdTunnel); @@ -61,12 +62,14 @@ namespace tunnel template typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; std::shared_ptr SelectNextHop (std::shared_ptr prevHop) const; - bool SelectPeers (std::vector >& hops); - + bool SelectPeers (std::vector >& hops, bool isInbound); + bool SelectExplicitPeers (std::vector >& hops, bool isInbound); + private: i2p::garlic::GarlicDestination * m_LocalDestination; int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels; + std::shared_ptr > m_ExplicitPeers; mutable std::mutex m_InboundTunnelsMutex; std::set, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first mutable std::mutex m_OutboundTunnelsMutex;