diff --git a/libi2pd/IdentMetrics.h b/libi2pd/IdentMetrics.h index dfc1d0c4..d69735bb 100644 --- a/libi2pd/IdentMetrics.h +++ b/libi2pd/IdentMetrics.h @@ -45,9 +45,11 @@ namespace data PeerOrdering (); ~PeerOrdering (); + void CleanUp (uint64_t ts); int GetPeerOrderingGroup (const IdentHash& routerIdent); - void CleanUp (uint64_t ts); + bool IsFirstHop (const IdentHash& routerIdent) { return !GetPeerOrderingGroup (routerIdent); }; + bool IsLastHop (const IdentHash& routerIdent) { return GetPeerOrderingGroup (routerIdent) & 0x02; }; // IBGW or OBEP private: diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f1651be2..3e4f32d9 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1190,13 +1190,19 @@ namespace data } std::shared_ptr NetDb::GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, - bool reverse, bool endpoint) const + bool reverse, bool endpoint, PeerOrdering * peerOrdering) const { bool checkIsReal = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < NETDB_TUNNEL_CREATION_RATE_THRESHOLD && // too low rate context.GetUptime () > NETDB_CHECK_FOR_EXPIRATION_UPTIME; // after 10 minutes uptime return GetRandomRouter ( - [compatibleWith, reverse, endpoint, checkIsReal](std::shared_ptr router)->bool + [compatibleWith, reverse, endpoint, checkIsReal, peerOrdering](std::shared_ptr router)->bool { + if (peerOrdering) + { + bool lastHop = peerOrdering->IsLastHop (router->GetIdentHash ()); + if (endpoint && !lastHop) return false; + if (lastHop && !endpoint && router->IsV4 ()) return false; // if router is eligible for endpoint but it's not + } return !router->IsHidden () && router != compatibleWith && (reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) : router->IsReachableFrom (*compatibleWith)) && !router->IsNAT2NATOnly (*compatibleWith) && diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index c60bcc24..6fde3644 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -33,6 +33,7 @@ #include "version.h" #include "util.h" #include "KadDHT.h" +#include "IdentMetrics.h" namespace i2p { @@ -94,7 +95,8 @@ namespace data std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse, bool endpoint, bool clientTunnel) const; - std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse, bool endpoint) const; + std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, + bool reverse, bool endpoint, PeerOrdering * peerOrdering = nullptr) const; std::shared_ptr GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set& excluded) const; std::shared_ptr GetRandomSSU2Introducer (bool v4, const std::unordered_set& excluded) const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::unordered_set& excluded, bool nextDay = false) const; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 57c47bc2..ccf01bfe 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1205,8 +1205,8 @@ namespace transport // try random peer if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL) { - int peerOrderingGroup = peerOrdering ? peerOrdering->GetPeerOrderingGroup (ident) : 0; - if (!peerOrderingGroup && filter (peer)) + bool eligibleForFirstHop = peerOrdering ? peerOrdering->IsFirstHop (ident) : true; + if (eligibleForFirstHop && filter (peer)) { foundIdent = ident; peer->lastSelectionTime = ts; @@ -1239,8 +1239,8 @@ namespace transport auto& [ident, peer] = peers[i]; if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL) { - int peerOrderingGroup = peerOrdering ? peerOrdering->GetPeerOrderingGroup (ident) : 0; - if (!peerOrderingGroup && filter (peer)) + bool eligibleForFirstHop = peerOrdering ? peerOrdering->IsFirstHop (ident) : true; + if (eligibleForFirstHop && filter (peer)) { foundIdent = ident; peer->lastSelectionTime = ts; @@ -1258,8 +1258,8 @@ namespace transport auto& [ident, peer] = peers[i]; if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL) { - int peerOrderingGroup = peerOrdering ? peerOrdering->GetPeerOrderingGroup (ident) : 0; - if (!peerOrderingGroup && filter (peer)) + bool eligibleForFirstHop = peerOrdering ? peerOrdering->IsFirstHop (ident) : true; + if (eligibleForFirstHop && filter (peer)) { foundIdent = ident; peer->lastSelectionTime = ts; @@ -1277,8 +1277,8 @@ namespace transport auto& [ident, peer] = peers[i]; if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL) { - int peerOrderingGroup = peerOrdering ? peerOrdering->GetPeerOrderingGroup (ident) : 0; - if (!peerOrderingGroup && filter (peer)) + bool eligibleForFirstHop = peerOrdering ? peerOrdering->IsFirstHop (ident) : true; + if (eligibleForFirstHop && filter (peer)) { foundIdent = ident; peer->lastSelectionTime = ts; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 67e10729..6f09ebe7 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -569,7 +569,7 @@ namespace tunnel } std::shared_ptr TunnelPool::SelectNextHop (std::shared_ptr prevHop, - bool reverse, bool endpoint) const + bool reverse, bool endpoint) { bool tryClient = !IsExploratory () && !i2p::context.IsLimitedConnectivity (); std::shared_ptr hop; @@ -577,7 +577,7 @@ namespace tunnel { hop = tryClient ? (m_IsHighBandwidth ? - i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint) : + i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint, &m_PeerOrdering) : i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, true)): i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, false); if (hop) diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 773ca760..99b61994 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -119,7 +119,7 @@ namespace tunnel std::shared_ptr GetLowestLatencyOutboundTunnel(std::shared_ptr exclude = nullptr) const; // for overriding tunnel peer selection - std::shared_ptr SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint) const; + std::shared_ptr SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint); bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop); private: