Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate classA Set of Hashes that automatically adds to the Set in theClientPeerSelector.IBGWExcluder.contains(Object)check.private classA Set of Hashes that automatically adds to the Set in the contains() check.private static final classExcluder + exclusion counts gathered once per selectPeers() call; exclude is wrapped by the hop helpers.private static final classImmutable selection parameters computed once perselectPeers(TunnelPoolSettings)call.Nested classes/interfaces inherited from class TunnelPeerSelector
TunnelPeerSelector.Excluder, TunnelPeerSelector.KeepAliveTally, TunnelPeerSelector.PreConnectOutcomeModifier and TypeClassDescriptionprotected classExcluder that automatically adds peers to the set when they should be excluded.(package private) static final classPer-cycle tally of why keepalive did not act on the peers it selected.(package private) static enumWhat a pre-connect probe actually achieved.Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final ConcurrentHashMap<Hash, Long> Tracks the last time preConnectTo was successfully called per peer.Accepts per tier since the last log line, so volume is visible.Last write time per accepted tier key, for rate limiting.private static final intFirst-hop quality attempts before accepting any tier-passing peer.(package private) static final doubleBuild success below which the first-hop quality loop starts one tier lower, accepting peers with only a connecting transport session rather than requiring an established one.(package private) static final doubleCross-pool diversity is only active when build success is above this threshold.(package private) static final intCross-pool diversity: when fast tier exceeds this count, exclude peers in ANY active tunnel across ALL pools to force each pool to use different fast peers.(package private) static final doubleCross-pool exclusion may not consume more than this fraction of the fast tier.private static final intFirst-hop quality attempts before preferring connecting peers.private static final intHow many first-hop candidates to fetch at once.private static final intMaximum first-hop diversity retries when concurrent builds exclude already-selected first hops.(package private) static final intSoft ceiling on_lastPreConnect.(package private) static final intMinimum non-self hops a selection needs to be buildable at all: the peer adjacent to us (IBGW for inbound, our first hop for outbound) and the far endpoint.private static final longPre-connect cooldown: peers connected within this window don't need pre-connect again.private static final StringConfig key for the legacy selection code.(package private) static final StringProperty to enable/disable conditional pre-connect in selectFirstHop.private static final booleanDefault: true.private static final StringConfig key naming the selection strategy.private static final doubleBuild success ratio entering severe attack mode.private static final longStartup grace period: strict first-hop gates and soft fallbacks are relaxed for the first 15 minutes.private static final StringStrategy name of the default selection.private static final StringStrategy name of the diversity selection.private static final StringStrategy name of the reliability selection.private static final longHow often the accepted-first-hop tier line may be written, per tier.(package private) static final doubleBuild success below which the first hop draws on both the Fast and HighCapacity tiers.(package private) static final intFast-tier size below which the first hop draws on both tiers regardless of build success.Fields inherited from class TunnelPeerSelector
_firstHopFails, _peerCooldowns, _provenResponders, ATTACK_RELAX_EXIT, ATTACK_THRESHOLD, FAILURE_MAP_MAX_SIZE, FIRST_HOP_FAIL_COOLDOWN_MS, MAX_WINDOW_MS, MIN_PROVEN_RESPONDER_COUNT, PEER_SELECTION_COOLDOWN_MS, PROVEN_RESPONDER_WINDOW_MS, QUALITY_RELAXED, QUALITY_STRICT, SCARCE_FAST_PEERS, STARTUP_WARNING_SUPPRESS_MS, WINDOW_MULTIPLIER_STATModifier and TypeFieldDescriptionTracks when a peer last failed as first hop.Shared cooldown map across all peer selectors.Peers whose most recent tunnel participation succeeded, mapped to the time of that success.(package private) static final doubleWhether the exclude caps are currently relaxed, and by how much build success has to recover before they are enforced again.protected static final doubleThreshold for detecting tunnel build attacks.protected static final intSize bound for the cooldown maps (TunnelPeerSelector._peerCooldowns,TunnelPeerSelector._firstHopFails,ExploratoryPeerSelector._exploratoryCooldowns).protected static final longPeers that failed as first hop (first hop unreachable) excluded for this long.static final longUpper bound on the activity window, applied after the multiplier.(package private) static final intMinimum proven-responder entries before cold-start seeding kicks in.protected static final longPeers selected within this window are excluded from further selection to ensure diversity.protected static final longRecency window for proven-responder proof.(package private) static final intMinimum evidence bar when builds are healthy.(package private) static final intMinimum evidence bar under stress: a live session or a recent successful tunnel test.static final intNumber of fast peers at or above which the peer set is considered well supplied and the activity window is never widened on availability grounds.protected static final longDuration in ms to suppress startup warnings.static final StringStat name for the live window multiplier.Fields inherited from class ConnectChecker
ANY_V4, ctx, logModifier and TypeFieldDescriptionstatic final intAny IPv4 transport.protected final RouterContextThe router context.protected final LogThe logger.Constructor Summary
ConstructorsConstructorDescriptionClientPeerSelector(RouterContext context) Creates the selector over the given router context.Method Summary
Modifier and TypeMethodDescriptionapplyShortfallFallbacks(TunnelPoolSettings settings, List<Hash> rv, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Progressive fallbacks when the selected peers are short of the requested length.buildExclusions(TunnelPoolSettings settings, boolean isInbound, double buildSuccess, int length) Build the lazy Excluder with client/shared cooldowns, first/last peer and pool diversity exclusions.buildLastHopExclude(ClientPeerSelector.SelectionParams params, Set<Hash> exclude) Build the last-hop exclusion set: closest-hop wrapped for inbound, OBEP wrapped for outbound.Builds the soft-fallback exclusion set: a copy of the first-hop exclusion set without no-signal-excluded peers that have proven track records (tunnel acceptance > 50% and at least one successful test), giving them a chance when all standard tiers fail.(package private) static booleancanUseStressFallback(double buildSuccess, boolean useHighCapPrimary, int rvSize) Whether the selection may use the progressive stress fallbacks and the shortened-tunnel allowance: network stress (build success below the attack threshold) or HighCap-primary mode, with at least one peer already selected.(package private) static voidClears the pre-connect history (for testing).private intcollectActive(List<Hash> rv, int min, ClientPeerSelector.SelectionExclusions ex) Pulls connected peers, which are not reachable through the profile tier cascade at all: a peer with an established transport session but no usable profile still builds fast.private intcollectFromTier(List<Hash> rv, int min, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) One cascading tier selection.(package private) static intcompareAcceptance(PeerProfile prof1, PeerProfile prof2) Acceptance ratio tiers: good (> 0.3) ranks above low (< 0.3), which ranks above dead (<= 0).(package private) static intcompareActivity(PeerProfile prof1, PeerProfile prof2, long now, long thirtyMinutes) Peers active within the activity window sort first.(package private) static intcompareExcluded(Hash p1, Hash p2, Set<Hash> exclude) Excluded peers sort last; two excluded peers compare equal.(package private) static intcompareLatency(float lat1, float lat2) Lower measured tunnel-test latency sorts first; measured beats unknown.(package private) static intcompareQuality(Hash p1, Hash p2, Set<Hash> exclude, PeerProfile prof1, PeerProfile prof2, Map<Hash, Long> proven, long now, long thirtyMinutes) Full quality comparison cascade.static intcompareReliability(PeerProfile prof1, PeerProfile prof2) Compare floodfill reliability: GOOD > OK > UNKNOWN > BAD.(package private) static intcompareSlowLatency(float lat1, float lat2) Peers with tunnel test latency over 15s sort last; when both are slow, the less slow one sorts first.(package private) static intcompareTestHistory(PeerProfile prof1, PeerProfile prof2) When both peers have unknown latency (lat=0), peers with a proven test history sort first.computeSelectionParams(TunnelPoolSettings settings, int length, boolean isInbound) Compute the shared selection parameters: tier priority, closest-hop checks, hidden flags and the IP restriction.private intfillRemainingHops(List<Hash> rv, int min, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Topsrvup tominhops from the tier ladder, inserting new middle hops before the vetted first hop so rv keeps its [endpoint ..filterBannedPeers(List<Hash> peers) Drop banlisted peers from a selection so builds do not dispatch requests that BuildHandler will reject with "Next peer is banned".filterByReliability(Set<Hash> candidates, Set<Hash> exclude) Filter candidates through the reliability gate: a peer must have an adequate acceptance ratio and at least one recent activity or connection signal to remain.filterGhostPeers(List<Hash> peers) Filter out ghost peers from the selected peer list.finalizeSelection(TunnelPoolSettings settings, List<Hash> rv, boolean isInbound) Insert self, ghost-filter, strategy post-processing, duplicate re-check, and cooldowns.findUnreliable(List<Hash> hops, long now) The selected hops that fail the reliability gate.private static intfirstHopIndex(List<Hash> rv, Hash firstHop) Index at which a missing middle hop must be inserted: just before the vetted first hop, or at the end when there is none yet.(package private) static intfirstHopQualityTier(int attempts, boolean inStartup, int currentTier) Build first-hop quality tier.private static StringformatPeerList(List<Hash> peers) Formats a peer list for the log.private StringReturns the configured peer selection strategy.(package private) static intinsertNewPeers(List<Hash> rv, int index, Collection<Hash> picked, int need) Adds up toneedpeers frompickedthat are not already inrv, inserting them atindexso the surrounding order is untouched.(package private) booleanisReliable(PeerProfile profile, long now, long tenMinutes, long thirtyMinutes) Reliability gate: the acceptance ratio must be at least 0.3, and the peer must show a recent tunnel-test success, recent activity, or an established connection.(package private) static booleanWhether the router is still in the startup grace period (firstSTARTUP_GRACE_MSms of uptime).private voidlogAcceptedFirstHopTier(RouterContext ctx, Hash firstHop, int tier, int attempt, int attempts, int remaining, double buildSuccess) Log the quality tier that actually produced this build's first hop.(package private) static intminRequestedLength(TunnelPoolSettings settings) Smallest tunnel the pool will accept: the configured length minus any negative variance, never below zero.positionalConflicts(List<Hash> nonSelf, boolean isInbound, Hash dest, long now) Selected hops whose placement would give a single peer concurrent entry and exit visibility across this destination's pools — the pairing that enables traffic correlation.provenCandidates(Set<Hash> excludePeers) Fresh proven responders, freshest first, filtered for basic eligibility: not us, not banlisted, not on selection cooldown, with a locally cached RouterInfo so a build can reach them, and not already active in the destination's pools (a swap must never introduce a per-pool duplicate).(package private) static intpruneStalePreConnect(ConcurrentHashMap<Hash, Long> map, long now) Drop pre-connect records older than the cooldown window.(package private) static voidrecordPreConnect(Hash peer, long time) Records that preConnectTo was called for the peer at the given time.private voidrefillFirstHop(ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches, boolean inStartup) Refill the first-hop candidate batch after a quality-loop ejection.private voidselectFirstHop(int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select the first hop, IBGW for inbound and the closest outbound peer otherwise, with a quality loop and pre-connect.selectHops(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Single-hop or multi-hop selection for one tunnel length.selectHopsWithRetry(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Draws every hop, drops unsuitable peers (ghost and banlisted), and redraws once from a fresh exclusion set when filtering emptied the selection.private booleanselectLastHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, Set<Hash> lastHopExclude, Set<Hash> rawExclude, ArraySet<Hash> matches) Select the last hop (hidden-inbound closest hop, hidden-outbound OBEP, or normal OBEP).private voidselectMiddleHops(int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches, List<Hash> rv) Select the middle hop(s) of a tunnel longer than 2 hops, subtiers 2-3, quality-ordered.selectMultiHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select all hops of a multi-hop tunnel: last hop, middle hops, then first hop.selectPeers(TunnelPoolSettings settings) Returns ENDPOINT FIRST, GATEWAY LAST!!!! In: us ..selectPeers(TunnelPoolSettings settings, Set<Hash> excludeFirstHops) Select peers for a new tunnel, excluding given peers from first-hop selection.selectPeersBase(TunnelPoolSettings settings) Select peers for a new tunnel.selectSingleHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select the single hop of a 1-hop tunnel (with hidden-inbound special case).(package private) static booleanshouldDiscardShortSelection(int rvSize, int min) Whether a post-finalize selection is too short to build and must be discarded for a redraw.(package private) static booleanshouldPreConnect(RouterContext ctx, Hash peer) Determines whether preConnectTo() should be called for a first-hop candidate.(package private) static booleanshouldRelaxCooldownToFirstHop(int usableTunnels, int length) Whether shared peer cooldowns should be relaxed to a first-hop-only filter: with at most one usable tunnel the pool is near-collapsed, and excluding checkTunnel-cooled peers from every hop can leave no selectable path at all.(package private) static booleanshouldWidenBothTiers(double buildSuccess, int fastPeers) Whether the first hop should draw candidates from both the Fast and HighCapacity tiers.private voidsortByPeerQuality(List<Hash> peers, Set<Hash> exclude) Sort peers by quality for tunnel building preference.private voidtopUpFromFastTier(ClientPeerSelector.SelectionParams params, Set<Hash> exclude, ArraySet<Hash> matches) Add Fast-tier candidates until the batch is full, used when the first hop is widening past the HighCapacity tier it started from.private voidtopUpFromHighCapacityTier(ClientPeerSelector.SelectionParams params, Set<Hash> exclude, ArraySet<Hash> matches) Add HighCapacity-tier candidates until the batch is full.(package private) static voidtrimToAcceptedFirstHop(ArraySet<Hash> matches, Hash accepted) Reduce a first-hop candidate batch to the single peer the quality loop accepted.private static booleanwasRecentlyConnected(RouterContext ctx, Hash peer) Check whether the peer was connected within the cooldown window.Methods inherited from class TunnelPeerSelector
addFreshCooldownExclusions, allowAsIBGW, allowAsOBEP, allowFirewalledUnderAttack, applyProbeFailure, checkTunnel, compareProven, countKnownCaps, dropUnreliable, filterSlow, formatExcludedPeers, getActivityWindow, getActivityWindow, getBuildSuccess, getClosestHopExclude, getExclude, getLength, getMaxWindowMultiplier, getPeersInAllPools, getPeersInPool, getWindowMultiplier, hasConnectivitySignal, hasConnectivitySignal, hasRecoveredFromFailure, hasTunnelLongerThanOne, hasValidTransportAddress, hasValidTransportAddress, isDuplicateSequence, isFirstHopFailing, isInStartupGracePeriod, isInStartupGracePeriod, isIPv6Only, isLowAcceptanceRatio, isOutdatedVersion, isProvenResponder, isStalePeer, isStalePeer, isUsableRouterAddress, isZeroHopSettings, keepAlive, matchesExistingTunnel, noteFirstHopRtt, orderPeers, preConnectTo, preferProven, prunePeerMaps, publishWindowMultiplier, recordFirstHopFail, regeneratePeers, relaxedExcludeCaps, relaxedExcludeCaps, requiredSignalQuality, seedProvenResponders, selectExplicit, setWindowMultiplier, shouldExclude, shouldExclude, shouldPreQual, shouldSelectExplicit, supportsNTCP2, windowMultiplierFor, windowMultiplierForModifier and TypeMethodDescriptionprotected static intAdd cooldown entries still inside their window (value > cutoff) to the exclusion set without mutating the map.protected booleanallowAsIBGW(Hash h) Should we allow as IBGW? This just checks for the "R" capability and IPv4 support.protected booleanallowAsOBEP(Hash h) Should we allow as OBEP? This just checks for IPv4 support.(package private) static booleanallowFirewalledUnderAttack(String capabilities, double buildSuccess) Should we allow a firewalled (U-cap) peer? During attacks (build success belowTunnelPeerSelector.ATTACK_THRESHOLD), allow U-cap peers that also publish M, N, O, P, or X capability.(package private) static voidapplyProbeFailure(RouterContext ctx, Hash peer) Act on a pre-connect probe that could not be delivered.protected booleancheckTunnel(boolean isInbound, boolean isExploratory, List<Hash> tunnel) Connectivity check.(package private) static intcompareProven(long t1, long t2, long now) Proven-responder comparison for the quality cascade: a peer whose last tunnel participation succeeded within the recency window sorts before one without; two peers on the same side compare equal so later cascade stages decide.(package private) static intcountKnownCaps(String cap) Count the meaningful capabilities a peer publishes, used to reject peers with no useful caps when there are plenty of fast peers.(package private) static booleandropUnreliable(List<Hash> hops, Set<Hash> unreliable, int minKeep) Remove unreliable hops while at leastminKeepremain.protected booleanfilterSlow(boolean isInbound, boolean isExploratory) Whether to skip peers that are slow.protected static StringformatExcludedPeers(Set<Hash> peers) Format a set of excluded peers for logging, with exclusion reasons when the set is anTunnelPeerSelector.ExcluderorExcluderBase.static longCompute the activity window for peer selection from the base ladder only, scaled by whatever multiplier the availability gate has granted.static longgetActivityWindow(RouterContext ctx, double buildSuccess) Compute the activity window for peer selection based on current network visibility.(package private) static doubleCurrent tunnel build success ratio, 1.0 when no data is available.getClosestHopExclude(boolean isInbound, Set<Hash> toAdd) Pick peers that we want to avoid for the first OB hop or last IB hop.getExclude(boolean isInbound, boolean isExploratory) Create the exclusion set for this pool, for passing to ProfileOrganizer.protected intgetLength(TunnelPoolSettings settings) Determine the tunnel length (number of hops).static intCeiling forTunnelPeerSelector.getWindowMultiplier().All non-self peers in active tunnels across ALL pools (client IB/OB + exploratory IB/OB).getPeersInPool(RouterContext ctx, TunnelPool pool) All non-self peers in active tunnels of the given pool.static intCurrent Tuner-controlled activity-window multiplier.(package private) static booleanhasConnectivitySignal(PeerProfile profile, long now, long activityWindow) Pre-qualification signal check: does the peer profile show recent connectivity evidence? Heard from or successfully sent to within the last 30 minutes, a successful tunnel test within the activity window, or any test history at all with a >50% acceptance ratio.(package private) static booleanhasConnectivitySignal(PeerProfile profile, long now, long activityWindow, boolean established, int quality) Pre-qualification signal check at the given strictness.protected static booleanhasRecoveredFromFailure(RouterContext ctx, Hash peer) Check if a peer has recovered from failure and can be reconsidered.protected static booleanTrue if the pool has at least one active tunnel longer than one hop.(package private) static booleanAddress half ofTunnelPeerSelector.hasValidTransportAddress(RouterContext, Hash), split out so a caller that already holds the RouterInfo does not have to probe the netdb a second time for the same entry.protected static booleanhasValidTransportAddress(RouterContext ctx, Hash peer) Check if a peer's RouterInfo has at least one reachable SSU or NTCP address.protected booleanisDuplicateSequence(TunnelPoolSettings settings, List<Hash> newPeers) Check if the selected peer sequence matches an existing tunnel in the pool.static booleanisFirstHopFailing(RouterContext ctx, Hash peer) Check if a peer recently failed as first hop and should be excluded.protected booleanConvenience instance method wrapping the static helper.static booleanIs the router in the startup grace period? During startup, peers haven't accumulated test history yet, so quality filters (pre-qualification, tier capping) should be relaxed to allow tunnels to build.protected booleanAre we IPv6 only?protected static booleanisLowAcceptanceRatio(RouterContext ctx, Hash peer) Check if a peer has a history of rejecting tunnel build requests.(package private) static booleanisOutdatedVersion(String version) True if the peer runs a version too old to interoperate: not the published version and older thanTunnelPeerSelector.MIN_VERSION.(package private) static booleanisProvenResponder(long lastJoin, long now) Whether a proven-join timestamp falls inside the recency window.(package private) static booleanisStalePeer(RouterContext ctx, Hash peer) Check whether a peer is stale — no contact (heard from or heard about) within the dynamic activity window.(package private) static booleanisStalePeer(RouterContext ctx, Hash peer, double buildSuccess) Check whether a peer is stale — no contact (heard from or heard about) within the dynamic activity window.(package private) static booleanIs the RouterAddress usable for tunnel building? SSU requires protocol v2 plus a valid IP/port or an introduction; SSU2 requires a valid IP/port or an introduction; NTCP/NTCP2 require a valid IP/port.protected static booleanisZeroHopSettings(TunnelPoolSettings settings) True if the settings describe a zero-hop pair: length <= 0, length override == 0, or length + variance <= 0.static voidkeepAlive(RouterContext ctx, boolean aggressive) Periodically called to keep transport sessions alive for top-tier peers and proactively establish connections to Fast/HighCap peers before builds need them.(package private) static booleanmatchesExistingTunnel(TunnelInfo existing, List<Hash> newPeers, boolean isInbound) Compare a newly selected peer sequence (excluding self) against one existing tunnel.(package private) static voidnoteFirstHopRtt(RouterContext ctx, Hash peer, Transport transport) Extract the transport's measured direct-link RTT and record it on the peer.protected voidorderPeers(List<Hash> rv, SessionKey key) Order peers using the given key.protected static TunnelPeerSelector.PreConnectOutcomepreConnectTo(RouterContext ctx, Hash peer) Send aDatabaseLookupMessageto a peer so it answers with our RouterInfo, which forces a full session handshake rather than the emptyDataMessagethat would leave the peer with nothing to reply to.(package private) static intpreferProven(List<Hash> hops, int from, int to, Map<Hash, Long> proof, long now, long window, Iterator<Hash> replacements) Replace hops lacking fresh proof with proven replacements, in order.protected static voidPrune expired entries from static peer maps.static voidPublish the current activity-window multiplier.protected static voidrecordFirstHopFail(RouterContext ctx, Hash peer) Record that a peer failed as first hop (first hop unreachable).regeneratePeers(TunnelPoolSettings settings, List<Hash> peers, int attempt) Regenerate tunnel peers to avoid duplicate sequence.(package private) static StringrelaxedExcludeCaps(String configured, double buildSuccess, long uptimeMs) Strip the M, N, O, D, P capability exclusions from the configured caps when the build success ratio is belowTunnelPeerSelector.ATTACK_THRESHOLDor the router is within its firstTunnelPeerSelector.STARTUP_WARNING_SUPPRESS_MSof uptime (when the ratio is not yet meaningful).(package private) static StringrelaxedExcludeCaps(String configured, double buildSuccess, long uptimeMs, boolean alreadyRelaxed) Strip the M, N, O, D, P capability exclusions from the configured caps when the build success ratio is belowTunnelPeerSelector.ATTACK_THRESHOLDor the router is within its firstTunnelPeerSelector.STARTUP_WARNING_SUPPRESS_MSof uptime (when the ratio is not yet meaningful).(package private) static intrequiredSignalQuality(double buildSuccess) Which quality of connectivity evidence a candidate must show to be pre-qualified, as a function of how well tunnel building is going.(package private) static voidseedProvenResponders(RouterContext ctx, long now) Seed the proven-responder map with random peers from the router's peer profiles when the map is belowTunnelPeerSelector.MIN_PROVEN_RESPONDER_COUNT.selectExplicit(TunnelPoolSettings settings, int length) For debugging, also possibly for restricted routes.static voidsetWindowMultiplier(int mult) Tuner-controlled activity-window multiplier, clamped to [1, 4] (TunnelPeerSelector.MIN_WINDOW_MULTIPLIER..TunnelPeerSelector.MAX_WINDOW_MULTIPLIER).static booleanshouldExclude(RouterContext ctx, RouterInfo peer) Should the peer be excluded based on its published caps, crypto, and version?static booleanshouldExclude(RouterContext ctx, RouterInfo peer, double buildSuccess) Should the peer be excluded based on its published caps, crypto, and version?(package private) static booleanshouldPreQual(boolean isExploratory, boolean inStartupGrace, double buildSuccess) Whether strict client-pool pre-qualification should be applied to a candidate peer.protected booleanshouldSelectExplicit(TunnelPoolSettings settings) For debugging, also possibly for restricted routes? Needs analysis and testing.protected static booleansupportsNTCP2(RouterContext ctx, Hash peer) Check if a peer supports NTCP2 transport.static intwindowMultiplierFor(int fastPeers, boolean startupGrace, int min, int max) Multiplier the peer-supply signal earns, independent of any build-outcome metric.static intTunnelPeerSelector.windowMultiplierFor(int, boolean, int, int)bound to the live router: reads the current fast-peer count and startup state.Methods inherited from class ConnectChecker
canConnect, canConnect, canConnect, getInboundMask, getOutboundMask, isNTCPDisabled, isSSUDisabledModifier and TypeMethodDescriptionbooleancanConnect(int ourMask, RouterInfo to) Can we connect to "to" based on published addresses?booleancanConnect(Hash from, Hash to) Can "from" connect to "to" based on published addresses?booleancanConnect(RouterInfo from, int ourMask) Can "from" connect to us based on published addresses?intOur inbound mask.intOur outbound mask.protected booleanIs NTCP disabled?protected booleanIs SSU disabled?
Field Details
SEVERE_ATTACK_THRESHOLD
private static final double SEVERE_ATTACK_THRESHOLDBuild success ratio entering severe attack mode.- See Also:
STARTUP_GRACE_MS
private static final long STARTUP_GRACE_MSStartup grace period: strict first-hop gates and soft fallbacks are relaxed for the first 15 minutes.- See Also:
ESTABLISHED_PREF_ATTEMPTS
private static final int ESTABLISHED_PREF_ATTEMPTSFirst-hop quality attempts before preferring connecting peers.- See Also:
CONNECTING_PREF_ATTEMPTS
private static final int CONNECTING_PREF_ATTEMPTSFirst-hop quality attempts before accepting any tier-passing peer.- See Also:
FIRST_HOP_CANDIDATES
private static final int FIRST_HOP_CANDIDATESHow many first-hop candidates to fetch at once.The quality loop can only iterate while it has a candidate to reject, so asking the tiers for exactly one left it a single attempt per refill and the 16-attempt budget went largely unspent. A small batch lets one tier scan serve several attempts. Only the accepted peer is kept. See the trim after the loop — so the rest never reach the tunnel.
- See Also:
WIDEN_BUILD_SUCCESS
static final double WIDEN_BUILD_SUCCESSBuild success below which the first hop draws on both the Fast and HighCapacity tiers.The two tiers hold different peers: Fast is speed-ranked, HighCapacity is proven-reliability. Below this the network is not delivering often enough for the distinction to earn its cost, and taking from only one of them needlessly halves the pool.
- See Also:
WIDEN_FAST_PEERS
static final int WIDEN_FAST_PEERSFast-tier size below which the first hop draws on both tiers regardless of build success.A small Fast tier cannot supply
FIRST_HOP_CANDIDATEScandidates however healthy the network looks, so the batch is worth completing from the other tier even when success is high. The same 300 marks the point where cross-pool diversity engages, so both decisions agree on what counts as a large enough Fast tier.- See Also:
CONNECTING_PREF_BUILD_SUCCESS
static final double CONNECTING_PREF_BUILD_SUCCESSBuild success below which the first-hop quality loop starts one tier lower, accepting peers with only a connecting transport session rather than requiring an established one.Distinct from
WIDEN_BUILD_SUCCESS: this widens the transport requirement, which costs build latency, so it waits until success is closer to healthy.- See Also:
TIER_LOG_INTERVAL_MS
private static final long TIER_LOG_INTERVAL_MSHow often the accepted-first-hop tier line may be written, per tier. @since 0.9.71+.- See Also:
_tierLogTime
_tierLogCount
PRECONNECT_COOLDOWN_MS
private static final long PRECONNECT_COOLDOWN_MSPre-connect cooldown: peers connected within this window don't need pre-connect again.- See Also:
MAX_PRECONNECT_MAP_SIZE
static final int MAX_PRECONNECT_MAP_SIZESoft ceiling on_lastPreConnect. Once exceeded, entries past the cooldown are swept, so the map cannot grow without bound across a long uptime as the router pre-connects to ever more distinct peers.- See Also:
PROP_PRECONNECT_OPTIMIZE
Property to enable/disable conditional pre-connect in selectFirstHop.- See Also:
PROP_PRECONNECT_OPTIMIZE_DEFAULT
private static final boolean PROP_PRECONNECT_OPTIMIZE_DEFAULTDefault: true.- See Also:
CROSS_POOL_DIVERSITY_THRESHOLD
static final int CROSS_POOL_DIVERSITY_THRESHOLDCross-pool diversity: when fast tier exceeds this count, exclude peers in ANY active tunnel across ALL pools to force each pool to use different fast peers.- See Also:
CROSS_POOL_BUILD_SUCCESS_MIN
static final double CROSS_POOL_BUILD_SUCCESS_MINCross-pool diversity is only active when build success is above this threshold. Higher thanTunnelPeerSelector.ATTACK_THRESHOLDbecause cross-pool exclusion is far more aggressive (excludes ALL active peers across ALL pools) and can starve builds when most fast peers are in active tunnels.- See Also:
CROSS_POOL_EXCLUSION_RATIO
static final double CROSS_POOL_EXCLUSION_RATIOCross-pool exclusion may not consume more than this fraction of the fast tier. When most fast peers are in active tunnels, natural pool-local diversity already provides enough variability — explicit exclusion risks starvation.- See Also:
PROP_LEGACY_SELECTION
Config key for the legacy selection code.- See Also:
PROP_STRATEGY
Config key naming the selection strategy.- See Also:
STRATEGY_DEFAULT
Strategy name of the default selection.- See Also:
STRATEGY_RELIABILITY
Strategy name of the reliability selection.- See Also:
STRATEGY_DIVERSITY
Strategy name of the diversity selection.- See Also:
MAX_DIVERSITY_RETRIES
private static final int MAX_DIVERSITY_RETRIESMaximum first-hop diversity retries when concurrent builds exclude already-selected first hops. Bounded so a near-total exclusion set cannot turn selection into a long loop.- See Also:
MIN_STRUCTURAL_NON_SELF_HOPS
static final int MIN_STRUCTURAL_NON_SELF_HOPSMinimum non-self hops a selection needs to be buildable at all: the peer adjacent to us (IBGW for inbound, our first hop for outbound) and the far endpoint. Matches thekeepAtLeastfloorTunnelPeerSelector.dropUnreliable(List, Set, int)already uses.- See Also:
_lastPreConnect
Tracks the last time preConnectTo was successfully called per peer.
Constructor Details
ClientPeerSelector
Creates the selector over the given router context.- Parameters:
context- the router context
Method Details
getStrategy
Returns the configured peer selection strategy.- Returns:
- the strategy name
formatPeerList
selectPeers
Returns ENDPOINT FIRST, GATEWAY LAST!!!! In: us .. closest .. middle .. IBGW Out: OBGW .. middle .. closest .. us.- Specified by:
selectPeersin classTunnelPeerSelector- Parameters:
settings- the tunnel pool settings- Returns:
- ordered list of Hash objects (one per peer) specifying what order they should appear in a tunnel (ENDPOINT FIRST). This includes the local router in the list. Never null; an empty list means no peers could be selected.
selectPeers
Select peers for a new tunnel, excluding given peers from first-hop selection. Used by the build executor's dispatch loop to ensure concurrent builds in the same batch target diverse first-hop peers — stacking multiple build requests on one peer floods it and makes the first build answer slower.The first hop is the last element of the returned list (endpoint-first order). If the selected first hop is excluded, selection retries up to
MAX_DIVERSITY_RETRIEStimes before returning the last result, so a caller always gets a usable set even when the exclusion set covers most of the tier.- Overrides:
selectPeersin classTunnelPeerSelector- Parameters:
settings- the pool's settings, supplying tunnel length, variance, depth, bandwidth and IP restriction for this selectionexcludeFirstHops- first-hop peers already targeted by concurrent builds in the same dispatch batch, may be null- Returns:
- ordered hops, endpoint first; empty when nothing usable exists
selectPeersBase
Select peers for a new tunnel. Delegates toselectPeers(TunnelPoolSettings, Set)with a null exclusion set.- Parameters:
settings- the pool's settings, supplying tunnel length, variance, depth, bandwidth and IP restriction for this selection- Returns:
- ordered hops, endpoint first; empty when nothing usable exists
shouldDiscardShortSelection
static boolean shouldDiscardShortSelection(int rvSize, int min) Whether a post-finalize selection is too short to build and must be discarded for a redraw.Pure decision helper for the shortfall guard in
selectPeers(), extracted for unit testing. A selection is discarded only when it holds fewer thanMIN_STRUCTURAL_NON_SELF_HOPSnon-self hops — that is, when it cannot form a tunnel regardless of what was requested. Anything longer is returned as a short tunnel, which the shortfall ladder already produces deliberately; discarding those to force a redraw converts a one-hop shortfall into a whole lost build cycle, and at minimum length (what a starved pool asks for) there is no slack to absorb it.- Parameters:
rvSize- selection size afterfinalizeSelection, including selfmin- minimum requested tunnel length, fromminRequestedLength(TunnelPoolSettings)- Returns:
- true if the selection must be discarded for a redraw
selectHopsWithRetry
private List<Hash> selectHopsWithRetry(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Draws every hop, drops unsuitable peers (ghost and banlisted), and redraws once from a fresh exclusion set when filtering emptied the selection. The retry is what turns "all chosen peers were unusable" from a wasted build cycle into a usable tunnel.- Parameters:
settings- the pool's settings, supplying tunnel length, variance, depth, bandwidth and IP restriction for this selectionlength- tunnel length being builtparams- shared selection parametersex- live exclusions, mutated so a retry cannot re-pick rejects- Returns:
- ordered hops, endpoint first; empty when nothing usable exists
selectHops
private List<Hash> selectHops(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Single-hop or multi-hop selection for one tunnel length. Never null.- Parameters:
settings- the pool's settings, deciding the single- or multi-hop pathlength- tunnel length being built; 1 selects a single hopparams- shared selection parameters for this attemptex- live exclusions, mutated by whichever path runs- Returns:
- ordered hops with the endpoint first, empty if nothing usable was found
computeSelectionParams
private ClientPeerSelector.SelectionParams computeSelectionParams(TunnelPoolSettings settings, int length, boolean isInbound) Compute the shared selection parameters: tier priority, closest-hop checks, hidden flags and the IP restriction.- Parameters:
settings- the pool's settings, source of the configured IP restrictionlength- tunnel length being built; a length of 1 or less clears the IP restriction outrightisInbound- true for an inbound tunnel, which decides which of the two hidden flags is set- Returns:
- the parameters shared by every hop selection of this attempt
buildExclusions
private ClientPeerSelector.SelectionExclusions buildExclusions(TunnelPoolSettings settings, boolean isInbound, double buildSuccess, int length) Build the lazy Excluder with client/shared cooldowns, first/last peer and pool diversity exclusions.- Parameters:
settings- the pool's settings, source of the destination and of the first/last peer exclusionsisInbound- true to use the inbound pool and its cooldown bookkeepingbuildSuccess- the tunnel build success ratio in [0.0, 1.0], fetched once per selectionlength- tunnel length being built, used to decide whether first-hop cooldowns may be relaxed- Returns:
- the exclusions to apply while selecting this tunnel's hops
shouldRelaxCooldownToFirstHop
static boolean shouldRelaxCooldownToFirstHop(int usableTunnels, int length) Whether shared peer cooldowns should be relaxed to a first-hop-only filter: with at most one usable tunnel the pool is near-collapsed, and excluding checkTunnel-cooled peers from every hop can leave no selectable path at all. The cooled peers stay filtered at first-hop selection (where the build actually contacts them). Middle and last hops may use them. Single-hop tunnels (no multi-hop quality loop) and unknown pools (negative count) never relax.- Parameters:
usableTunnels- usable tunnels in this pool, or -1 when the pool is unknownlength- tunnel length being selected for- Returns:
- true when cooldowns should apply to the first hop only
selectSingleHop
private List<Hash> selectSingleHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select the single hop of a 1-hop tunnel (with hidden-inbound special case).- Parameters:
settings- the pool's settings; not consulted on this pathlength- tunnel length, used as the draw size for the fallback tiersparams- shared selection parameters, deciding the hidden and closest-hop pathsex- live exclusions; the wrapped exclude set is written back for the shortfall fallbackmatches- the pre-sized accumulator the tier draws fill- Returns:
- the hop in a list, empty when no tier could supply a peer
selectMultiHop
private List<Hash> selectMultiHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select all hops of a multi-hop tunnel: last hop, middle hops, then first hop. rv ends up [endpoint .. first hop]. The vetted first hop is recorded onexso a shortfall fill inserts middles before it instead of shifting roles. A missing first hop is logged and left for that fill — discarding the whole selection would waste a usable endpoint and middles.- Parameters:
settings- the pool's settings, source of the random key and the destination used for sub-tier placementlength- tunnel length being built, two or moreparams- shared selection parameters for this attemptex- live exclusions; the vetted first hop is recorded on itmatches- scratch accumulator, cleared and reused for each hop group- Returns:
- the hops ordered endpoint first, empty if no last hop was found
buildLastHopExclude
Build the last-hop exclusion set: closest-hop wrapped for inbound, OBEP wrapped for outbound.- Parameters:
params- shared selection parameters, deciding the wrapper and whether the closest-hop check appliesexclude- the live exclusion set to wrap- Returns:
- the wrapped exclusions used when picking the last hop
selectLastHop
private boolean selectLastHop(TunnelPoolSettings settings, int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, Set<Hash> lastHopExclude, Set<Hash> rawExclude, ArraySet<Hash> matches) Select the last hop (hidden-inbound closest hop, hidden-outbound OBEP, or normal OBEP).- Parameters:
settings- the pool's settings, source of the destination whose inbound pool is consultedlength- tunnel length being built, used for the two-hop sub-tier splitparams- shared selection parameters, deciding which last-hop role appliesrandomKey- the tunnel's random key for sub-tier placement, not consulted herelastHopExclude- wrapped exclusions (closest-hop / OBEP role checks)rawExclude- the unwrapped exclusion set, used only for the final recovery pass when the wrapper excluded every candidatematches- accumulator filled with the chosen last hop- Returns:
- false to abort the selection
selectMiddleHops
private void selectMiddleHops(int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches, List<Hash> rv) Select the middle hop(s) of a tunnel longer than 2 hops, subtiers 2-3, quality-ordered.- Parameters:
length- tunnel length; the middle count is length minus twoparams- shared selection parameters, deciding which tier leads the drawrandomKey- key used to order the chosen middles, so their sequence is specific to this tunnelex- live exclusions, extended with the peers chosen herematches- accumulator for the middle draws, cleared on the way outrv- the hop list built so far; the ordered middles are appended to it
selectFirstHop
private void selectFirstHop(int length, ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches) Select the first hop, IBGW for inbound and the closest outbound peer otherwise, with a quality loop and pre-connect.- Parameters:
length- tunnel length, not consulted on this pathparams- shared selection parameters: tier priority, hidden flags and the IP restrictionrandomKey- the tunnel's random key, used when refilling a rejected first hopex- live exclusions; first-hop cooldowns are read from it and rejections are added back to itmatches- accumulator filled with the chosen first hop, left empty if none passed the quality loop
trimToAcceptedFirstHop
Reduce a first-hop candidate batch to the single peer the quality loop accepted.When the loop accepted a candidate it is the one to keep, and it is the head of the set because every attempt takes
iterator().next(). When nothing was accepted the loop has already ejected everything it vetted and rejected, so whatever remains was never cleared — kept deliberately rather than discarded, since returning empty costs the cycle a build outright.No side effects beyond the set, so unit tests exercise it directly.
- Parameters:
matches- the candidate batch, modified to hold at most the accepted peeraccepted- the peer the quality loop accepted, or null if none was
shouldWidenBothTiers
static boolean shouldWidenBothTiers(double buildSuccess, int fastPeers) Whether the first hop should draw candidates from both the Fast and HighCapacity tiers.True when the network is struggling, or when the Fast tier is too small to fill the candidate batch on its own. Either way, taking from one tier alone needlessly shrinks the pool the quality loop chooses from.
Pure decision — no context access, safe for unit tests.
- Parameters:
buildSuccess- the build success ratio in [0.0, 1.0]fastPeers- the current Fast-tier size- Returns:
- whether to take candidates from both tiers
topUpFromFastTier
private void topUpFromFastTier(ClientPeerSelector.SelectionParams params, Set<Hash> exclude, ArraySet<Hash> matches) Add Fast-tier candidates until the batch is full, used when the first hop is widening past the HighCapacity tier it started from.Passes the batch's full size and lets the selector compute the shortfall — the same accounting
ProfileOrganizer.remainingToSelect(int, Set)does for every other caller, so the top-up cannot drift from the tiers beneath it.- Parameters:
params- shared selection parameters, source of the IP restriction and the subnet accumulator the draw must respectexclude- peers the batch draw must skipmatches- the first-hop batch, topped up to FIRST_HOP_CANDIDATES entries
topUpFromHighCapacityTier
private void topUpFromHighCapacityTier(ClientPeerSelector.SelectionParams params, Set<Hash> exclude, ArraySet<Hash> matches) Add HighCapacity-tier candidates until the batch is full. SeetopUpFromFastTier(ClientPeerSelector.SelectionParams, Set, ArraySet).- Parameters:
params- shared selection parameters, source of the IP restriction and setexclude- peers the batch draw must skipmatches- the first-hop batch being filled
refillFirstHop
private void refillFirstHop(ClientPeerSelector.SelectionParams params, SessionKey randomKey, ClientPeerSelector.SelectionExclusions ex, ArraySet<Hash> matches, boolean inStartup) Refill the first-hop candidate batch after a quality-loop ejection. Tries the same tier cascade as selectFirstHop (HighCap → Fast → Active → NotFailing) with the ejected peer excluded, so the slot isn't wasted. At most 3 refills per build cycle.Refills the whole
FIRST_HOP_CANDIDATESbatch rather than a single peer. The quality loop is budgeted for 16 attempts, and a batch that shrinks by one per ejection reaches that budget by draining rather than by exhausting it: with a batch of 4 and three refills of one, only seven candidates are ever examined and the remaining nine attempts — plus the degraded-candidate fallback behind them — never run.- Parameters:
params- the tier cascade flags, held constant across every refillrandomKey- random key for Fast tier sub-tieringex- exclusion set (ejected peer added by caller)matches- empty set to populate with a fresh batchinStartup- true if still in startup grace period
isStartupGracePeriod
Whether the router is still in the startup grace period (firstSTARTUP_GRACE_MSms of uptime). The startup grace relaxes the number of quality attempts (fewer candidates early on) but does not skip hard-fail gates: first-hop-failing peers, stale peers, and the established/connecting preference are still enforced to avoid selecting unreliable tunnel targets.Pure decision — no side effects.
- Parameters:
ctx- the router context- Returns:
- whether the router is within the startup grace period
shouldPreConnect
Determines whether preConnectTo() should be called for a first-hop candidate. Returns false (skip pre-connect) when the build timeout is sufficient to survive the ~8.5s SSU2 handshake, the peer was recently connected, or the feature is disabled. Returns true when pre-connect is needed to ensure reliable tunnel delivery.Approach 1: If the request timeout exceeds
15s, the message survives the handshake, so skip pre-connect. Approach 3: Property toggle allows runtime disabling. Approach 4: Recently connected peers don't need pre-connect again.The timeout is read through
BuildRequestor.getRequestTimeout(RouterContext)so it reflects the budget the builder actually runs with, including runtime tuning. Readingctx.getPropertyhere instead saw neither the tuned value nor a configured one: with the property unset its own default equalled the threshold, so the comparison was always true and first-hop pre-connect never ran on a default install.Pure decision — no side effects.
- Parameters:
ctx- the router contextpeer- the first-hop candidate- Returns:
- whether preConnectTo() should be called for this peer
wasRecentlyConnected
Check whether the peer was connected within the cooldown window.- Parameters:
ctx- the router contextpeer- the peer to check- Returns:
- true if the peer was established or connecting recently
recordPreConnect
Records that preConnectTo was called for the peer at the given time.- Parameters:
peer- the peer that was pre-connectedtime- the router clock value to store as the peer's last pre-connect
clearPreConnectHistory
static void clearPreConnectHistory()Clears the pre-connect history (for testing).pruneStalePreConnect
Drop pre-connect records older than the cooldown window. An entry is only ever read as "connected within the lastPRECONNECT_COOLDOWN_MS" (seewasRecentlyConnected(RouterContext, Hash)), so once it ages past that window it can never change a decision again — it is dead weight. Without this sweep the map grows with every distinct peer the router pre-connects to over its lifetime. Weakly-consistent iteration, so it never blocks a concurrentrecordPreConnect(Hash, long).- Parameters:
map- the pre-connect history to prune in placenow- the router clock value to age entries against- Returns:
- the number of entries removed
logAcceptedFirstHopTier
private void logAcceptedFirstHopTier(RouterContext ctx, Hash firstHop, int tier, int attempt, int attempts, int remaining, double buildSuccess) Log the quality tier that actually produced this build's first hop.The first-hop quality ladder relaxes its reachability requirement as attempts accumulate: tiers 0 and 1 require the peer to be established or connecting, tier 2 requires neither. A gateway taken at tier 2 is therefore one we have no transport session with, and cannot receive a build request — which is indistinguishable, from the outside, from a peer that went silent. This line is the only way to tell those apart after the fact.
Rate limited to one line per
TIER_LOG_INTERVAL_MSper tier so a busy build loop cannot turn the diagnosis into the noise it is meant to explain; the counters accumulate regardless and are reported in the same line. The limiter usescomputerather thanreplace(k, old, new):replaceis a no-op returning false when the key is absent, so the first log for each tier would never happen and the key would never be inserted.- Parameters:
ctx- the router contextfirstHop- the accepted gateway, or null if none was acceptedtier- the tier it was accepted at, or -1attempt- the attempt number it was accepted on, or -1attempts- total quality attempts maderemaining- candidates left in the setbuildSuccess- the tunnel build success ratio, reported in the log line
firstHopQualityTier
static int firstHopQualityTier(int attempts, boolean inStartup, int currentTier) Build first-hop quality tier. Pure so the ladder is testable.Tier 0 and 1 require an established or connecting peer; tier 2 requires neither. The ladder reaches tier 2 after
CONNECTING_PREF_ATTEMPTSrejections, which is the point where an unreachable gateway stops being filtered out.- Parameters:
attempts- 1-based quality attempt countinStartup- whether the router is inside its startup grace periodcurrentTier- the tier to start from- Returns:
- the tier to apply for this attempt
buildSoftFallbackExclude
private Set<Hash> buildSoftFallbackExclude(Set<Hash> exclude, ClientPeerSelector.SelectionExclusions ex) Builds the soft-fallback exclusion set: a copy of the first-hop exclusion set without no-signal-excluded peers that have proven track records (tunnel acceptance > 50% and at least one successful test), giving them a chance when all standard tiers fail. No side effects.- Parameters:
exclude- the current first-hop exclusion setex- the selection exclusions with the per-peer reason map- Returns:
- the reduced exclusion set
canUseStressFallback
static boolean canUseStressFallback(double buildSuccess, boolean useHighCapPrimary, int rvSize) Whether the selection may use the progressive stress fallbacks and the shortened-tunnel allowance: network stress (build success below the attack threshold) or HighCap-primary mode, with at least one peer already selected. Pure decision — no side effects.- Parameters:
buildSuccess- current tunnel build success rateuseHighCapPrimary- whether the selection prefers high-capacity peersrvSize- current number of selected peers- Returns:
- whether stress fallbacks may be attempted
applyShortfallFallbacks
private List<Hash> applyShortfallFallbacks(TunnelPoolSettings settings, List<Hash> rv, int length, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Progressive fallbacks when the selected peers are short of the requested length.- Parameters:
settings- the pool's settings, source of the minimum acceptable lengthrv- the hops chosen so far, ordered endpoint firstlength- the tunnel length that was requestedparams- shared selection parameters, deciding which stress fallbacks are allowedex- live exclusions and the vetted first hop the fills are ordered around- Returns:
- the extended hop list, or an empty list when the shortfall cannot be filled
fillRemainingHops
private int fillRemainingHops(List<Hash> rv, int min, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) Topsrvup tominhops from the tier ladder, inserting new middle hops before the vetted first hop so rv keeps its [endpoint .. first hop] order.The ladder only ever widens on genuine scarcity: banlisted, ghost, first-hop-failing and chronically failing peers are rejected by the tier gates before a candidate is ever collected, so a wider tier is more peers, not lower quality. Unsuitable peers are therefore excluded from selection rather than discovered afterwards.
- Parameters:
rv- the partial selection, endpoint first and non-emptymin- the minimum hop count to reachparams- selection parameters (tier priority, stress level)ex- live exclusions and the vetted first hop- Returns:
- number of hops added
collectFromTier
private int collectFromTier(List<Hash> rv, int min, ClientPeerSelector.SelectionParams params, ClientPeerSelector.SelectionExclusions ex) One cascading tier selection. The ProfileOrganizer tiers fall through to wider tiers internally (Fast -> HighCap -> NotFailing -> all peers), so a single call with the right entry tier covers the whole ladder.- Parameters:
rv- the hop list to extend; new peers go in before the vetted first hopmin- total hops the selection needs, counted against rv's current sizeparams- shared selection parameters, deciding whether HighCap or Fast leadsex- live exclusions, extended with the peers taken here- Returns:
- number of hops added
collectActive
Pulls connected peers, which are not reachable through the profile tier cascade at all: a peer with an established transport session but no usable profile still builds fast.- Parameters:
rv- the hop list to extendmin- total hops the selection needs, counted against rv's current sizeex- live exclusions the draw must skip- Returns:
- number of hops added
firstHopIndex
Index at which a missing middle hop must be inserted: just before the vetted first hop, or at the end when there is none yet.- Parameters:
rv- the hop list being filledfirstHop- the vetted first hop, or null when none was selected- Returns:
- the index of firstHop in rv, or rv.size() when it is absent
insertNewPeers
Adds up toneedpeers frompickedthat are not already inrv, inserting them atindexso the surrounding order is untouched. Mutates onlyrv.- Parameters:
rv- the selection to extendindex- insert position, clamped to the list boundspicked- candidate peers, order preservedneed- maximum number to insert- Returns:
- number of peers inserted
minRequestedLength
Smallest tunnel the pool will accept: the configured length minus any negative variance, never below zero. Pure decision — no side effects.- Parameters:
settings- the pool's settings, supplying tunnel length, variance, depth, bandwidth and IP restriction for this selection- Returns:
- minimum hop count for this pool
finalizeSelection
Insert self, ghost-filter, strategy post-processing, duplicate re-check, and cooldowns. Quality-sorts the non-self hops for inbound selections only (see below).- Parameters:
settings- the pool settings for the tunnel being builtrv- the selected peers, reordered and filtered in placeisInbound- true for a client pool tunnel, false for the exploratory pool- Returns:
- the finalized peer list with this router inserted at the inbound or outbound end, or an empty list if the tunnel check failed
filterByReliability
Filter candidates through the reliability gate: a peer must have an adequate acceptance ratio and at least one recent activity or connection signal to remain. The input order is preserved. Ranking is left to the caller's quality sort so each reliability signal plays a single role.- Parameters:
candidates- peers to filterexclude- peers to exclude- Returns:
- list of peers passing the reliability gate, in input order
provenCandidates
Fresh proven responders, freshest first, filtered for basic eligibility: not us, not banlisted, not on selection cooldown, with a locally cached RouterInfo so a build can reach them, and not already active in the destination's pools (a swap must never introduce a per-pool duplicate).- Parameters:
excludePeers- peers to exclude because they are already active in this destination's tunnels- Returns:
- eligible proven candidates for hop swaps, never null
positionalConflicts
Selected hops whose placement would give a single peer concurrent entry and exit visibility across this destination's pools — the pairing that enables traffic correlation. Two rules are checked:- inbound selection: the chosen IBGW already serves as the OBEP of one of our active outbound tunnels
- outbound selection: the chosen OBEP already serves as the IBGW of one of our active inbound tunnels
- Parameters:
nonSelf- the selected non-self peers, gateway-first orderisInbound- true when selecting for an inbound tunneldest- the destination hash, or nullnow- current time from the router clock- Returns:
- conflicting peers, possibly empty
findUnreliable
The selected hops that fail the reliability gate. Peers without a profile are unknown rather than poor — they are never returned.- Parameters:
hops- the selected non-self peersnow- current time from the router clock- Returns:
- the subset failing the reliability gate, never null
isReliable
Reliability gate: the acceptance ratio must be at least 0.3, and the peer must show a recent tunnel-test success, recent activity, or an established connection. Each signal is consulted exactly once.- Parameters:
profile- the peer profile (may be null)now- current time from the router clocktenMinutes- tunnel-test recency window in msthirtyMinutes- activity recency window in ms- Returns:
- true if the peer passes the reliability gate
sortByPeerQuality
Sort peers by quality for tunnel building preference. Higher quality peers (recently tested, active, connected) sort first.- Parameters:
peers- the selected peers, reordered in place; nothing happens when the list is null or emptyexclude- peers to push to the end of the list, or null
compareQuality
static int compareQuality(Hash p1, Hash p2, Set<Hash> exclude, PeerProfile prof1, PeerProfile prof2, Map<Hash, Long> proven, long now, long thirtyMinutes) Full quality comparison cascade. Stage order is significant — each stage short-circuits the ones below it: excluded last, then proven responders (recent successful participation), then acceptance ratio, slow tunnel-test latency, activity recency, and latency.- Parameters:
p1- peer on the left of the comparisonp2- peer on the right of the comparisonexclude- peers to deprioritize, or nullprof1- first peer's profile, or nullprof2- second peer's profile, or nullproven- local snapshot mapping peer hash to proven-responder timestamp; must not be the live shared map, or the sort's contract can be violated mid-flight by build-thread writesnow- current time from the router clockthirtyMinutes- activity window in ms- Returns:
- negative, zero, or positive
compareReliability
Compare floodfill reliability: GOOD > OK > UNKNOWN > BAD. Unproven floodfills sort lower to reduce load on them until their reliability is established.- Parameters:
prof1- first peer's profile, or nullprof2- second peer's profile, or null- Returns:
- negative if p1 is more reliable, positive if p2 is more reliable, 0 if equal
compareExcluded
compareAcceptance
Acceptance ratio tiers: good (> 0.3) ranks above low (< 0.3), which ranks above dead (<= 0). Missing profiles default to 1.0.- Parameters:
prof1- first peer's profile, or nullprof2- second peer's profile, or null- Returns:
- negative, zero, or positive
compareSlowLatency
static int compareSlowLatency(float lat1, float lat2) Peers with tunnel test latency over 15s sort last; when both are slow, the less slow one sorts first. 0 latency means no data (unknown).- Parameters:
lat1- first peer's tunnel test time averagelat2- second peer's tunnel test time average- Returns:
- negative, zero, or positive
compareActivity
Peers active within the activity window sort first.- Parameters:
prof1- first peer's profile, or nullprof2- second peer's profile, or nullnow- current time from the router clockthirtyMinutes- activity window in ms- Returns:
- negative, zero, or positive
compareLatency
static int compareLatency(float lat1, float lat2) Lower measured tunnel-test latency sorts first; measured beats unknown. When both latencies are 0 (unknown), peers that have been tested before (have a persisted test timestamp) sort before never-tested peers, so proven peers with expired latency data are preferred over new peers.- Parameters:
lat1- first peer's tunnel test time averagelat2- second peer's tunnel test time average- Returns:
- negative, zero, or positive
compareTestHistory
When both peers have unknown latency (lat=0), peers with a proven test history sort first. Uses the persisted EWMA update timestamp to distinguish tested peers from never-tested peers.- Parameters:
prof1- first peer's profile, or nullprof2- second peer's profile, or null- Returns:
- negative, zero, or positive
filterGhostPeers
filterBannedPeers
Drop banlisted peers from a selection so builds do not dispatch requests that BuildHandler will reject with "Next peer is banned". MirrorsfilterGhostPeers(List): an all-banned selection returns empty so the caller can redraw from usable candidates instead of dispatching a build that cannot succeed.- Parameters:
peers- the list of selected peers (excluding self)- Returns:
- filtered list without banlisted peers; empty when all were banned