- All Implemented Interfaces:
TunnelInfo
- Direct Known Subclasses:
PooledTunnelCreatorConfig
See PooledTunnelCreatorConfig for the non-abstract class.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumWhy a tunnel that would normally be dropped by the early-expiry gate was instead admitted for one last-chance test.Field Summary
Modifier and TypeFieldDescriptionprivate final byte[][]AES reply IVs, by hop.private final SessionKey[]AES reply keys, by hop.private HashBlank hash used for the reply keys.private byte[][]ChaCha20 reply additional data, by hop.private SessionKey[]ChaCha20 reply keys, by hop.private final HopConfig[]Gateway first.protected final RouterContextThe router context.private final longWall-clock time this config was created, i.e.private final HashOnly necessary for client tunnels.private StringOptional pool nickname for log display.private longWhen the tunnel expires.private final AtomicIntegerHard failures counted on the tunnel.private booleanOne-shot escalation latch: once the streak reachedFIRST_HOP_FAILURE_THRESHOLDthe caller is told exactly once.private final AtomicIntegerRaw count of spaced first-hop send failures.private MessageWrapper.OneTimeSessionGarlic reply keys for the outbound endpoint only.private final booleanTrue for an inbound tunnel.private longWhen the tunnel entered the last chance window.private longDeadline of the last chance window.Reason the tunnel was given a last chance.private longWall-clock time of the most recent counted first-hop send failure, 0 if none.private intMost recent latency sample, in ms, -1 if none.private longWhen the tunnel last carried real (non-test) traffic, or 0 if never.private longWall-clock time of the most recent soft best-effort timeout, 0 if none.private longWall clock (ms) of the last production byte, volatile for the same reason as_verifiedBytesTransferred.private intLatency samples recorded so far.private final int[]Ring of the recent latency samples.private intWrite index into the latency ring.private longWhen the local transport session was first seen missing.private booleanWhether a transport session to our local hop existed when this tunnel entered the pool.private LogLogger for the tunnel.private final AtomicIntegerMessages processed on the tunnel.private booleanTrue when the tunnel needs an expedited test.The hop order of the tunnel.private final LongAdderBytes verified on this tunnel since the last per-peer profile update.private longWall clock (ms) of the last per-peer profile update.private final Hash[]Gateway first.private intPre-connect retries already spent in the current window.private longStart of the current pre-connect retry window, 0 until the first retry.private intPriority of the tunnel for bandwidth and builds.private intRecent-traffic test exemptions used.private longMessage id the build reply arrives on.private booleanTrue if the tunnel was reused for another pool.private final AtomicIntegerSoft failures counted on the tunnel.private TunnelTestStatusCurrent test status of the tunnel.private final LongAdderTotal verified bytes on this tunnel.static final intCeiling forincrementTestFailures().static final longMinimum spacing between first-hop send failures that count towardsFIRST_HOP_FAILURE_THRESHOLD.static final intConsecutive first-hop send failures before an outbound tunnel is retired.static final longWindow in which spaced first-hop send failures accumulate, mirroringSOFT_FAILURE_WINDOW_MS.private static final intLatency samples kept per tunnel.static final intMaximum consecutive test failures before the tunnel is retired.(package private) static final intCeiling for the soft failure streak.private static final longWindow over which this tunnel's throughput is totaled before the per-peer profiles are updated, in ms.static final intIV length forgetAESReplyIV(int).(package private) static final longWindow in which soft best-effort send timeouts accumulate into a consecutive streak (status-3 timeouts only.Constructor Summary
ConstructorsConstructorDescriptionTunnelCreatorConfig(RouterContext ctx, int length, boolean isInbound) For exploratory only (null destination).TunnelCreatorConfig(RouterContext ctx, int length, boolean isInbound, Hash destination) Allocates the hop configs and peer arrays for the given length.Method Summary
Modifier and TypeMethodDescriptionvoidaddLatencySample(int ms) Add a latency sample from a test result.voidadmitLastChance(long now, TunnelCreatorConfig.LastChanceReason reason) Admit this tunnel for a last-chance test despite its remaining life being inside the early-expiry window.booleanclaimPreConnectRetry(long now, int maxRetries, long windowMs) Claim one of at mostmaxRetriespre-connect retries for this tunnel, forgetting retries older thanwindowMs.voidClear the expedited test flag after running the expedited test.voidReset the first-hop send failure streak and re-arm the escalation latch.voidRevoke the last-chance admission (test settled, or no longer needed).voidReset the soft streak: verified traffic proves the tunnel carries data, so congestion timeouts recorded before it no longer count.voidReset the consecutive failure counter and mark the tunnel as GOOD.private voidcoalescePeakThroughput(long now) Periodically push this tunnel's throughput into the per-peer profiles.(package private) static inteffectiveFirstHopFailures(int raw, long lastCounted, long now, long windowMs) Effective first-hop send failure streak for a raw count stamped at a point in time.(package private) static inteffectiveSoftFailures(int raw, long lastSoftFailure, long now, long windowMs) Effective soft-failure streak for a raw count stamped at a point in time.voidfirstHopSendFailureStreak(int streak) Hook invoked whenever the first-hop send failure streak advances.byte[]getAESReplyIV(int hop) IV used to encrypt the reply sent for the tunnel creation crypto.getAESReplyKey(int hop) Key to encrypt the reply sent for the tunnel creation crypto.intThe average latency of the last 3 tests.Checksum for blank record.byte[]getChaChaReplyAD(int hop) The ECIES reply associated data for the given hop, or null.getChaChaReplyKey(int hop) The ECIES reply key for the given hop, or null.getConfig(int hop) Retrieve the config for the given hop.intThe number of consecutive test failures.longWhen this tunnel was built, in wall-clock ms.If this is a client tunnel, what destination is it for?Pool nickname for this tunnel, or null if not set.For convenience.longThe tunnel expiration, in ms since the epoch.For convenience.intEffective first-hop send failure streak, with failures older thanFIRST_HOP_FAILURE_WINDOW_MSdecayed out at read time.(package private) intgetFirstHopSendFailures(long now) Timestamped form ofgetFirstHopSendFailures().ECIES short OBEP record only.For convenience.longWhen the last-chance admission was granted (ms), or 0 if never.longWhen the last-chance admission expires (deadline snapshot).Why this tunnel was admitted for a last-chance test.intThe last recorded test latency.longWhen the tunnel last carried real traffic.longWhen we last sent or received data on this tunnel.intHow many hops are there in the tunnel? INCLUDING US.longWhen the local transport session was first seen missing, or 0 when present.The tunnel pool options.getPeer(int hop) Retrieve the peer at the given hop (the gateway is hop 0).intOutbound message priority - for outbound tunnels only.intThe number of messages pumped through this tunnel.getReceiveTunnelId(int hop) Retrieve the tunnelId that the given hop receives messages on.intThe number of recent-traffic test exemptions used.longThe message ID for the new style reply.Component ordering in the new style request.getSendTunnelId(int hop) Retrieve the tunnelId that the given hop sends messages on.intSoft best-effort timeout count, with failures older thanSOFT_FAILURE_WINDOW_MSdecayed out at read time (the time-windowed form of the streak — no sweep required).The current test status of this tunnel for UI display.booleanHas the tunnel failed completely?intThe consecutive failure count.longThe total verified bytes transferred on this tunnel.booleanWhether this tunnel held a transport session to its local hop when it was built.booleanWhether at least 3 latency samples have been collected.voidTake note of a message being pumped through this tunnel.voidIncrement the recent-traffic test exemption counter.voidIncrement the soft best-effort timeout counter only.voidIncrement the failure count without triggering pool removal or reuse flag.voidincrementVerifiedBytesTransferred(int bytes) Record thatbytesmoved through this tunnel, counting as real traffic: it also stamps the last-real-traffic clock thatgetLastTransferred()reports and the data-verified test trust in TestJob keys off.voidincrementVerifiedBytesTransferred(int bytes, boolean realTraffic) Record thatbytesmoved through this tunnel, optionally counting as real traffic.booleanisEC(int hop) Is it an ECIES hop?booleanIs this an inbound tunnel?booleanisLastChanceAdmitted(long now) Is a last-chance test admission still valid atnow? Only expiration shortens the window.booleanWhether the tunnel needs an expedited test due to slow detection.(package private) static intnextFirstHopFailureCount(int raw, long lastCounted, long now, long spacingMs, long windowMs) Next first-hop failure count for a send failure arriving atnow, folding in both the decay window and the spacing rule.intRecord a failed send to the first hop of an outbound tunnel.(package private) intrecordFirstHopSendFailure(long now) Timestamped form ofrecordFirstHopSendFailure(), so spacing, decay and latching are testable without real waits.voidRecord that the tunnel carried real traffic.voidThe tunnel appeared slow, so flag it for an expedited test.voidsetAESReplyKeys(int hop, SessionKey key, byte[] iv) Key and IV to encrypt the reply sent for the tunnel creation crypto.voidsetBlankHash(Hash h) Checksum for blank record.voidsetChaChaReplyKeys(int hop, SessionKey key, byte[] ad) The ECIES reply key and associated data for the given hop.voidsetDestinationNickname(String name) Optional display nickname for this tunnel (e.g.voidsetExpiration(long when) The tunnel expiration, in ms since the epoch.voidECIES short OBEP record only.voidsetLastLatency(int ms) The latency of the last completed test.voidsetLocalHopMissingSince(long when) Record or clear when the local transport session was first seen missing.voidsetLocalHopSessionEstablished(boolean established) Record whether a transport session to the local hop existed at build time.voidThe peer at the given hop.voidsetPriority(int priority) Outbound message priority - for outbound tunnels only.voidsetReplyMessageId(long id) The message ID for the new style reply.voidsetReplyOrder(List<Integer> order) The component ordering for the new style request.voidNote that we reused this tunnel.voidCalled when a test fails.voidMark the tunnel FAILING regardless of the hard-failure counter.voidMark tunnel as scheduled for early expiry due to pool being over budget.voidCalled when a test is started.voidMark tunnel as scheduled for early expiry (pruned from pool).voidtestSuccessful(int ms) Mark the tunnel as GOOD, recording the latency of the successful test.Compact one-line tunnel identifier for log output: role, client or exploratory, nickname and short destination.toString()Human-readable description of the tunnel, its peers, and its state.Render every hop, its peer, and its tunnel IDs, for a full description.booleanThe tunnel failed a test, so (maybe) stop using it.voidThe tunnel failed completely, so definitely stop using it.voidWe failed to contact the first hop for an outbound tunnel, so immediately stop using it.booleanDid we reuse this tunnel?
Field Details
_context
The router context._destination
Only necessary for client tunnels._config
Gateway first._peers
Gateway first._expiration
private volatile long _expirationWhen the tunnel expires._order
_replyMessageId
private long _replyMessageIdMessage id the build reply arrives on._isInbound
private final boolean _isInboundTrue for an inbound tunnel._messagesProcessed
Messages processed on the tunnel._verifiedBytesTransferred
_lastTransferredTime
private volatile long _lastTransferredTimeWall clock (ms) of the last production byte, volatile for the same reason as_verifiedBytesTransferred._preConnectWindowStart
private long _preConnectWindowStartStart of the current pre-connect retry window, 0 until the first retry. Guarded bythisalong with_preConnectRetries._preConnectRetries
private int _preConnectRetriesPre-connect retries already spent in the current window._creationTime
private final long _creationTimeWall-clock time this config was created, i.e. when its build started. Lets the test cycle give a freshly built tunnel a grace period before its results count against it. A tunnel cannot fairly be judged on a round trip it had no realistic chance to complete. Deliberately not onTunnelInfo: the test cycle is the only reader, and adding a method to a public interface for one caller would break out-of-tree implementors._failures
Hard failures counted on the tunnel._softFailures
Soft failures counted on the tunnel._lastSoftFailure
private volatile long _lastSoftFailureWall-clock time of the most recent soft best-effort timeout, 0 if none. WithSOFT_FAILURE_WINDOW_MSthis bounds the soft streak at read time: a failure older than the window decays out of the count, so a tunnel that times out once in a while forever is never degraded or rotated out, while a genuine burst still reaches the degraded and removal bars._firstHopSendFailures
Raw count of spaced first-hop send failures. Decay and spacing are applied at read time, seerecordFirstHopSendFailure()._lastFirstHopSendFailure
private volatile long _lastFirstHopSendFailureWall-clock time of the most recent counted first-hop send failure, 0 if none. Only stamped when the count actually advances, so a burst cannot keep pushing the spacing deadline forward and never reach the threshold._firstHopFailed
private volatile boolean _firstHopFailedOne-shot escalation latch: once the streak reachedFIRST_HOP_FAILURE_THRESHOLDthe caller is told exactly once. The send-failure job is shared by every message on the tunnel and is only deduped while queued, so without this a single burst would calltunnelFailedFirstHop()for each failed message._testStatus
Current test status of the tunnel._reused
private volatile boolean _reusedTrue if the tunnel was reused for another pool._priority
private volatile int _priorityPriority of the tunnel for bandwidth and builds._localHopSessionEstablished
private volatile boolean _localHopSessionEstablishedWhether a transport session to our local hop existed when this tunnel entered the pool. Recorded once at build time by the pool, then read-only.See
TunnelInfo.hadLocalHopSession()for why the pool needs the build-time fact rather than the current session state._localHopMissingSince
private volatile long _localHopMissingSinceWhen the local transport session was first seen missing. Zero when the session is present, which is also the state for a tunnel that never lost it._peakThroughputCurrentTotal
Bytes verified on this tunnel since the last per-peer profile update. ALongAdderbecause it is bumped once per 1KB fragment and does not need the monitor guarding_peakThroughputLastCoallesce._peakThroughputLastCoallesce
private volatile long _peakThroughputLastCoallesceWall clock (ms) of the last per-peer profile update. Written under the tunnel monitor bycoalescePeakThroughput(long)but read without it, so that the per-fragment path can skip the monitor, hence volatile._blankHash
Blank hash used for the reply keys._ChaReplyKeys
ChaCha20 reply keys, by hop._ChaReplyADs
private byte[][] _ChaReplyADsChaCha20 reply additional data, by hop._AESReplyKeys
AES reply keys, by hop._AESReplyIVs
private final byte[][] _AESReplyIVsAES reply IVs, by hop._garlicReplyKeys
Garlic reply keys for the outbound endpoint only._log
Logger for the tunnel.REPLY_IV_LENGTH
MAX_CONSECUTIVE_TEST_FAILURES
public static final int MAX_CONSECUTIVE_TEST_FAILURESMaximum consecutive test failures before the tunnel is retired.- See Also:
SOFT_FAILURE_WINDOW_MS
static final long SOFT_FAILURE_WINDOW_MSWindow in which soft best-effort send timeouts accumulate into a consecutive streak (status-3 timeouts only. Hard dispatch failures useMAX_CONSECUTIVE_TEST_FAILURES). A soft failure older than this is decayed out of the count, bounding both the degraded bar (TunnelPool.SOFT_DEGRADED_FOR_ENSURE) and the soft removal bar so sparse congestion timeouts over a long tunnel lifetime can never retire a tunnel that carries data when it is sent.- See Also:
MAX_SOFT_FAILURES
static final int MAX_SOFT_FAILURESCeiling for the soft failure streak. The count exists only to cross the soft removal bar, so saturating well above it costs nothing and stops a retained tunnel that keeps timing out from reporting a streak long enough to be mistaken for a count of independent failures.- See Also:
FIRST_HOP_FAILURE_THRESHOLD
public static final int FIRST_HOP_FAILURE_THRESHOLDConsecutive first-hop send failures before an outbound tunnel is retired. Send failures are not proof the tunnel is dead: most come from local congestion (expired-on-queue, CoDel drops, no-bid replies) and land on a shared job that runs once per failed message, so the bar sits above a single burst. The count is spaced out byFIRST_HOP_FAILURE_SPACING_MSso a local stall collapses to 1 while a genuinely unreachable first hop reaches the bar on its own withinFIRST_HOP_FAILURE_WINDOW_MS.- See Also:
FAILURE_COUNT_CEILING
public static final int FAILURE_COUNT_CEILINGCeiling forincrementTestFailures(). Comfortably above the largest removal threshold any caller can compute (degraded mode with a thin pool), so saturation never changes a decision. It only stops the reported count from drifting.- See Also:
FIRST_HOP_FAILURE_SPACING_MS
public static final long FIRST_HOP_FAILURE_SPACING_MSMinimum spacing between first-hop send failures that count towardsFIRST_HOP_FAILURE_THRESHOLD. Failures closer together are one event, so a burst of 40 messages failing in the same second records 1, not 40.- See Also:
FIRST_HOP_FAILURE_WINDOW_MS
public static final long FIRST_HOP_FAILURE_WINDOW_MSWindow in which spaced first-hop send failures accumulate, mirroringSOFT_FAILURE_WINDOW_MS. A failure older than this is decayed out at read time, so an idle tunnel that finally loses a send never inherits an unbounded streak.- See Also:
PEAK_THROUGHPUT_COALESCE_MS
private static final long PEAK_THROUGHPUT_COALESCE_MSWindow over which this tunnel's throughput is totaled before the per-peer profiles are updated, in ms. Matches the windowPeerProfilecoalesces its own peak throughput on.- See Also:
LATENCY_SAMPLE_SIZE
private static final int LATENCY_SAMPLE_SIZELatency samples kept per tunnel.- See Also:
_lastLatency
private volatile int _lastLatencyMost recent latency sample, in ms, -1 if none._latencyHistory
private final int[] _latencyHistoryRing of the recent latency samples._latencyIdx
private volatile int _latencyIdxWrite index into the latency ring._latencyCount
private volatile int _latencyCountLatency samples recorded so far._needsExpeditedTest
private volatile boolean _needsExpeditedTestTrue when the tunnel needs an expedited test._recentTestExemptions
private volatile int _recentTestExemptionsRecent-traffic test exemptions used. A tunnel with recent verified data gets a few free passes on test failures (reply-path false negatives), but not unlimited — after one exemption, failures count normally so the tunnel doesn't become immortal._destinationNickname
Optional pool nickname for log display._lastRealTraffic
private volatile long _lastRealTrafficWhen the tunnel last carried real (non-test) traffic, or 0 if never. Updated only at the real traffic delivery sites. Inbound data arrival (InboundEndpointProcessor) and outbound message dispatch (OutboundClientMessageOneShotJob) — never by TestJob, so test traffic cannot pollute the proof that the tunnel works._lastChanceReason
Reason the tunnel was given a last chance._lastChanceDeadline
private volatile long _lastChanceDeadlineDeadline of the last chance window._lastChanceAdmission
private volatile long _lastChanceAdmissionWhen the tunnel entered the last chance window.
Constructor Details
TunnelCreatorConfig
For exploratory only (null destination).- Parameters:
ctx- the router contextlength- 1 minimum (0 hop is length 1)isInbound- true to build an inbound tunnel
TunnelCreatorConfig
Allocates the hop configs and peer arrays for the given length.- Parameters:
ctx- the router contextlength- 1 minimum (0 hop is length 1)isInbound- true to build an inbound tunneldestination- null for exploratory
Method Details
setDestinationNickname
Optional display nickname for this tunnel (e.g. pool name like I2PSnark).- Parameters:
name- the nickname to show in logs
getDestinationNickname
Pool nickname for this tunnel, or null if not set.- Returns:
- the pool nickname if set, null otherwise
getLength
public int getLength()How many hops are there in the tunnel? INCLUDING US. i.e. one more than the TunnelCreatorConfig length.- Specified by:
getLengthin interfaceTunnelInfo- Returns:
- the number of hops, counting ourselves as one
getOptions
getConfig
Retrieve the config for the given hop. the gateway is hop 0.- Parameters:
hop- the hop number, gateway is 0- Returns:
- the config for that hop, non-null
getReceiveTunnelId
Retrieve the tunnelId that the given hop receives messages on. the gateway is hop 0.- Specified by:
getReceiveTunnelIdin interfaceTunnelInfo- Parameters:
hop- zero-based position in the tunnel, 0 being the gateway- Returns:
- the receive tunnel id
getSendTunnelId
Retrieve the tunnelId that the given hop sends messages on. the gateway is hop 0.- Specified by:
getSendTunnelIdin interfaceTunnelInfo- Parameters:
hop- zero-based position in the tunnel, 0 being the gateway- Returns:
- the send tunnel id
getPeer
Retrieve the peer at the given hop (the gateway is hop 0).- Specified by:
getPeerin interfaceTunnelInfo- Parameters:
hop- the hop number, gateway is 0- Returns:
- the peer at that hop
setPeer
The peer at the given hop.- Parameters:
hop- the hop number, gateway is 0peer- the peer to use at that hop
getGateway
For convenience.- Specified by:
getGatewayin interfaceTunnelInfo- Returns:
- getPeer(0)
getEndpoint
For convenience.- Specified by:
getEndpointin interfaceTunnelInfo- Returns:
- getPeer(
getLength()- 1)
getFarEnd
For convenience.- Specified by:
getFarEndin interfaceTunnelInfo- Returns:
isInbound()? getGateway() : getEndpoint()
isInbound
public boolean isInbound()Is this an inbound tunnel?- Specified by:
isInboundin interfaceTunnelInfo- Returns:
- true if peers at the far end send to us through this tunnel
getDestination
If this is a client tunnel, what destination is it for?- Specified by:
getDestinationin interfaceTunnelInfo- Returns:
- null for exploratory
getExpiration
public long getExpiration()The tunnel expiration, in ms since the epoch.- Specified by:
getExpirationin interfaceTunnelInfo- Returns:
- the time the tunnel expires, in ms since the epoch
setExpiration
public void setExpiration(long when) The tunnel expiration, in ms since the epoch.- Specified by:
setExpirationin interfaceTunnelInfo- Parameters:
when- expiration time in milliseconds since epoch
hadLocalHopSession
public boolean hadLocalHopSession()Whether this tunnel held a transport session to its local hop when it was built. False when never recorded.- Specified by:
hadLocalHopSessionin interfaceTunnelInfo- Returns:
- true when a local-hop session was established at build time
setLocalHopSessionEstablished
public void setLocalHopSessionEstablished(boolean established) Record whether a transport session to the local hop existed at build time.- Specified by:
setLocalHopSessionEstablishedin interfaceTunnelInfo- Parameters:
established- the session state observed when the tunnel entered the pool
getLocalHopMissingSince
public long getLocalHopMissingSince()When the local transport session was first seen missing, or 0 when present.- Specified by:
getLocalHopMissingSincein interfaceTunnelInfo- Returns:
- the time in ms the session was first seen missing, or 0
setLocalHopMissingSince
public void setLocalHopMissingSince(long when) Record or clear when the local transport session was first seen missing.- Specified by:
setLocalHopMissingSincein interfaceTunnelInfo- Parameters:
when- the time in ms, or 0 to mark the session present
getReplyOrder
setReplyOrder
getReplyMessageId
public long getReplyMessageId()The message ID for the new style reply.- Returns:
- the reply message ID, 0 when none has been set
setReplyMessageId
public void setReplyMessageId(long id) The message ID for the new style reply.- Parameters:
id- the message ID to return to the client
incrementProcessedMessages
public void incrementProcessedMessages()Take note of a message being pumped through this tunnel.getProcessedMessagesCount
public int getProcessedMessagesCount()The number of messages pumped through this tunnel.- Specified by:
getProcessedMessagesCountin interfaceTunnelInfo- Returns:
- the processed messages count
incrementVerifiedBytesTransferred
public void incrementVerifiedBytesTransferred(int bytes) Record thatbytesmoved through this tunnel, counting as real traffic: it also stamps the last-real-traffic clock thatgetLastTransferred()reports and the data-verified test trust in TestJob keys off. Only the real delivery paths — inbound data arrival and outbound message dispatch — may call this.- Specified by:
incrementVerifiedBytesTransferredin interfaceTunnelInfo- Parameters:
bytes- bytes counted against the tunnel
incrementVerifiedBytesTransferred
public void incrementVerifiedBytesTransferred(int bytes, boolean realTraffic) Record thatbytesmoved through this tunnel, optionally counting as real traffic.The distinction matters because two things read this state. The throughput profile wants *every* byte, including the 1024 a test round pushes, or the per-peer throughput figures understate a busy tunnel. The data-verified test trust wants *only* real traffic, because it reads
getLastTransferred()to decide the tunnel has proven itself in production. When the test round called the unconditional form, a passing test stamped the real-traffic clock on the tunnel under test — which for an outbound test is the tunnel itself — so a tunnel that had never carried a single production byte could grant itself the trust that is meant to mean the opposite.- Parameters:
bytes- bytes counted against the tunnelrealTraffic- true when this is production traffic, false for test or synthetic traffic
coalescePeakThroughput
private void coalescePeakThroughput(long now) Periodically push this tunnel's throughput into the per-peer profiles.Run once a minute from
incrementVerifiedBytesTransferred(int, boolean), crediting bothtunnelDataPushed()(raw period bytes) andtunnelDataPushed1m()(that total normalized to a minute): both are pure sums, so bulk crediting equals per-fragment crediting.- Parameters:
now- wall clock at the call site, already compared against the coalesce deadline so the fast path never gets here
getVerifiedBytesTransferred
public long getVerifiedBytesTransferred()The total verified bytes transferred on this tunnel.- Specified by:
getVerifiedBytesTransferredin interfaceTunnelInfo- Returns:
- the verified bytes transferred
getLastTransferred
public long getLastTransferred()When we last sent or received data on this tunnel.- Returns:
- the last transferred
claimPreConnectRetry
public boolean claimPreConnectRetry(long now, int maxRetries, long windowMs) Claim one of at mostmaxRetriespre-connect retries for this tunnel, forgetting retries older thanwindowMs.A first hop with no transport session re-dispatches the whole build through BuildRequestor.preConnectFallback(), and each retry costs a full request timeout. Nothing bounded that, so a dead first hop retried forever and kept the tunnel pinned in the pool's in-progress set. The window is what makes the bound fair: a tunnel that fails once every few minutes keeps its retry, while a runaway loop, which retries on every timeout, spends its budget and stops.
- Parameters:
now- current time in msmaxRetries- retries one window may spend, 0 disables retryingwindowMs- how long a spent retry is remembered- Returns:
- true if a retry was claimed, false if the budget is already spent
getCreationTime
public long getCreationTime()When this tunnel was built, in wall-clock ms. Never zero, so a caller asking "is this young" needs no null or unset case.- Returns:
- creation time in ms since the epoch
recordRealTraffic
public void recordRealTraffic()Record that the tunnel carried real traffic. Real data proves the tunnel works, so any soft best-effort streak accumulated before it is cleared alongside it.It also refills the recent-traffic test exemption budget. That budget is spent when a test fails while the tunnel demonstrably carried data — a reply-path false negative rather than evidence against the tunnel — and it used to be refilled only by
testSuccessful(int), so a tunnel that could never answer a test but could still carry data got exactly one free pass for its whole lifetime and was then condemned by failures it had no way to clear. Traffic is the stronger proof: the inbound caller only fires after the tunnel's crypto verified, and the outbound caller only fires after the remote peer ACKed.Status itself is not touched here — see
TunnelPool.clearFailingOnTraffic(), which owns promotion back to GOOD.- Specified by:
recordRealTrafficin interfaceTunnelInfo
getLastRealTraffic
public long getLastRealTraffic()When the tunnel last carried real traffic.- Specified by:
getLastRealTrafficin interfaceTunnelInfo- Returns:
- the timestamp, or 0 if it never carried real traffic
tunnelFailed
public boolean tunnelFailed()The tunnel failed a test, so (maybe) stop using it.- Returns:
- false if we stopped using it, true if still ok
incrementTestFailures
public void incrementTestFailures()Increment the failure count without triggering pool removal or reuse flag. Used when a previously GOOD tunnel fails a retest — we want to track the failure for selection deprioritization but keep the tunnel alive for further testing and data delivery.The count saturates. Every caller compares the result against a removal threshold, so once that threshold is passed the extra increments change no decision — they only made the counter (and the log line quoting it) grow without bound. A condemned-but-retained tunnel kept retesting reached counts in the hundreds, which made a saturated metric impossible to read and hid the real failure ratio.
- Specified by:
incrementTestFailuresin interfaceTunnelInfo
incrementSoftFailures
public void incrementSoftFailures()Increment the soft best-effort timeout counter only. Soft status-3 must not tripgetTunnelFailed()or selection gates that key on the hard/test counter. Congestion is not tunnel death. The streak is time-windowed: a failure that arrives afterSOFT_FAILURE_WINDOW_MSwithout one starts the count over at 1 instead of extending an aging streak forever.- Specified by:
incrementSoftFailuresin interfaceTunnelInfo
getSoftFailures
public int getSoftFailures()Soft best-effort timeout count, with failures older thanSOFT_FAILURE_WINDOW_MSdecayed out at read time (the time-windowed form of the streak — no sweep required).- Specified by:
getSoftFailuresin interfaceTunnelInfo- Returns:
- the effective soft failure count
clearSoftFailures
public void clearSoftFailures()Reset the soft streak: verified traffic proves the tunnel carries data, so congestion timeouts recorded before it no longer count. Called fromrecordRealTraffic()andclearTestFailures(), never fromtestSuccessful(int)— a passing test exercises the test path, not the data path.effectiveSoftFailures
static int effectiveSoftFailures(int raw, long lastSoftFailure, long now, long windowMs) Effective soft-failure streak for a raw count stamped at a point in time. Pure decision helper so the decay rule is unit-testable without waiting out the real window.- Parameters:
raw- stored soft failure count, <= 0 means nonelastSoftFailure- wall-clock time of the most recent soft failure (ms), <= 0 means nonenow- current wall-clock time (ms)windowMs- window in which soft failures accumulate (ms)- Returns:
- the count to act on: 0 once the streak has aged out
effectiveFirstHopFailures
static int effectiveFirstHopFailures(int raw, long lastCounted, long now, long windowMs) Effective first-hop send failure streak for a raw count stamped at a point in time. Same time-windowed decay rule aseffectiveSoftFailures(int, long, long, long)— both are read-time filters over a raw counter, so no sweep is required.- Parameters:
raw- stored first-hop failure count, <= 0 means nonelastCounted- wall-clock time of the most recent counted failure (ms), <= 0 means nonenow- current wall-clock time (ms)windowMs- window in which first-hop failures accumulate (ms)- Returns:
- the count to act on: 0 once the streak has aged out
nextFirstHopFailureCount
static int nextFirstHopFailureCount(int raw, long lastCounted, long now, long spacingMs, long windowMs) Next first-hop failure count for a send failure arriving atnow, folding in both the decay window and the spacing rule. Pure decision helper so the burst/stale behaviour is unit-testable without real waits.- Parameters:
raw- stored first-hop failure count, <= 0 means nonelastCounted- wall-clock time of the most recent counted failure (ms), <= 0 means nonenow- current wall-clock time (ms)spacingMs- minimum spacing between counted failures (ms)windowMs- window in which first-hop failures accumulate (ms)- Returns:
- the new count (>= 1), or -1 when this failure is a burst duplicate inside the spacing interval and must not be counted
recordFirstHopSendFailure
public int recordFirstHopSendFailure()Record a failed send to the first hop of an outbound tunnel.Called from the outbound send-failure job, which fires for every non-requeueable send failure (expired on queue, CoDel drop, no-bid reply, dropped message). Most of which are local congestion, not a dead peer. Counting raw would retire the tunnel on one bad second, so the streak is decayed by
FIRST_HOP_FAILURE_WINDOW_MSand spaced byFIRST_HOP_FAILURE_SPACING_MS.- Returns:
- -1 if not applicable (inbound or zero-hop tunnel), 0 if this failure changed nothing (inside the spacing interval, or the threshold was already reached and escalated), otherwise the current streak; a return value of
FIRST_HOP_FAILURE_THRESHOLDor more means the caller must fail the tunnel, and it is only handed that signal once untilclearFirstHopFailures()re-arms it
recordFirstHopSendFailure
int recordFirstHopSendFailure(long now) Timestamped form ofrecordFirstHopSendFailure(), so spacing, decay and latching are testable without real waits.- Parameters:
now- wall-clock time (ms) of this failure- Returns:
- see
recordFirstHopSendFailure()
getFirstHopSendFailures
public int getFirstHopSendFailures()Effective first-hop send failure streak, with failures older thanFIRST_HOP_FAILURE_WINDOW_MSdecayed out at read time.- Returns:
- the streak count, 0 if none
getFirstHopSendFailures
int getFirstHopSendFailures(long now) Timestamped form ofgetFirstHopSendFailures().- Parameters:
now- wall-clock time (ms) to evaluate the decay against- Returns:
- the streak count, 0 if none
clearFirstHopFailures
public void clearFirstHopFailures()Reset the first-hop send failure streak and re-arm the escalation latch. Only a data-carrying send proves the path to the first hop works, so the sole caller isrecordRealTraffic().A passing test deliberately does not clear the streak: the round trip proves the peer is not dead, but not that it is not flaky, and a first hop that alternates fail/pass/fail/pass would never accumulate to
FIRST_HOP_FAILURE_THRESHOLDif every pass reset it. Staleness is handled by theFIRST_HOP_FAILURE_WINDOW_MSread-time decay instead, which ages out a genuinely dead peer's old failures without making accumulation impossible for a merely flaky one.This differs from
clearSoftFailures(), which likewise is never called fromtestSuccessful(int)for the same reason.tunnelFailedCompletely
public void tunnelFailedCompletely()The tunnel failed completely, so definitely stop using it.tunnelFailedFirstHop
public void tunnelFailedFirstHop()We failed to contact the first hop for an outbound tunnel, so immediately stop using it. For outbound non-zero-hop tunnels only.Base hook: marks the tunnel as failed. Subclasses with a pool (PooledTunnelCreatorConfig) also notify the pool of the failure.
firstHopSendFailureStreak
public void firstHopSendFailureStreak(int streak) Hook invoked whenever the first-hop send failure streak advances. Gives subclasses a chance to re-warm the path to the first hop: the failure may be a local stall rather than a dead peer, and a fresh transport session makes the next send likely to land. Not invoked for burst duplicates, so callers see at most one hook perFIRST_HOP_FAILURE_SPACING_MS.The caller invokes this before it acts on the threshold, so the streak handed in may equal
FIRST_HOP_FAILURE_THRESHOLD; a subclass that only wants to re-warm a tunnel that is still going to be kept alive must filter on the value itself — seePooledTunnelCreatorConfig.shouldPreConnect(int).Base config has no pool and nothing to warm; see
PooledTunnelCreatorConfig.- Parameters:
streak- the current streak, from 1 up to and includingFIRST_HOP_FAILURE_THRESHOLD
getTunnelFailed
public boolean getTunnelFailed()Has the tunnel failed completely?- Specified by:
getTunnelFailedin interfaceTunnelInfo- Returns:
- the tunnel failed
getTunnelFailures
public int getTunnelFailures()The consecutive failure count.- Returns:
- the tunnel failures
clearTestFailures
public void clearTestFailures()Reset the consecutive failure counter and mark the tunnel as GOOD. Called only on traffic proof. Never bytestSuccessful(int), which reaches GOOD by being tested rather than by carrying data — so it also restores the recent-traffic test exemption budget alongside the soft streak: a tunnel promoted back from FAILING/FAILED must resume normal service with a clean slate, not inherit the spend that produced the mark.getRecentTestExemptions
public int getRecentTestExemptions()The number of recent-traffic test exemptions used.- Returns:
- the recent test exemptions
incrementRecentTestExemptions
public void incrementRecentTestExemptions()Increment the recent-traffic test exemption counter.testSuccessful
public void testSuccessful(int ms) Mark the tunnel as GOOD, recording the latency of the successful test. Clears any last-chance admission — the test settled, so the early-expiry gate no longer needs the bypass. Does NOT clear the soft streak: a test exercises the test path, not the data path.Does NOT clear the first-hop send-failure streak. A passing test is evidence the peer is not dead, but not evidence it is not flaky — a flaky first hop that alternates fail/pass/fail/pass would never reach the failure threshold if each pass reset the streak. The 60s decay window (FIRST_HOP_FAILURE_WINDOW_MS) already ages the streak naturally, so a genuinely dead peer's old failures expire without making accumulation impossible for a merely flaky one.
- Specified by:
testSuccessfulin interfaceTunnelInfo- Parameters:
ms- the response time in milliseconds
wasReused
public boolean wasReused()Did we reuse this tunnel?- Specified by:
wasReusedin interfaceTunnelInfo- Returns:
- true if the tunnel came from an existing pool rather than a fresh build
setReused
public void setReused()Note that we reused this tunnel.- Specified by:
setReusedin interfaceTunnelInfo
getPriority
public int getPriority()Outbound message priority - for outbound tunnels only.- Returns:
- -25 to +25, default 0
setPriority
public void setPriority(int priority) Outbound message priority - for outbound tunnels only.- Parameters:
priority- -25 to +25, default 0
setAESReplyKeys
Key and IV to encrypt the reply sent for the tunnel creation crypto.- Parameters:
hop- the hop number, gateway is 0key- the key to encrypt the reply withiv- the 16 byte IV- Throws:
IllegalArgumentException- if iv not 16 bytes
getAESReplyKey
Key to encrypt the reply sent for the tunnel creation crypto. Null for short build record.- Parameters:
hop- the hop number, gateway is 0- Returns:
- key or null
- Throws:
IllegalArgumentException- if iv not 16 bytes
getAESReplyIV
public byte[] getAESReplyIV(int hop) IV used to encrypt the reply sent for the tunnel creation crypto. Null for short build record.- Parameters:
hop- the hop number, gateway is 0- Returns:
- 16 bytes or null
getBlankHash
setBlankHash
Checksum for blank record.- Parameters:
h- the hash to use for a blank record
setLastLatency
public void setLastLatency(int ms) The latency of the last completed test.- Parameters:
ms- latency in milliseconds
getLastLatency
public int getLastLatency()The last recorded test latency.- Specified by:
getLastLatencyin interfaceTunnelInfo- Returns:
- latency in milliseconds, or -1 if not available
addLatencySample
public void addLatencySample(int ms) Add a latency sample from a test result.- Parameters:
ms- latency in milliseconds
getAverageLatency
public int getAverageLatency()The average latency of the last 3 tests.- Returns:
- average latency in ms, or -1 if no tests yet
hasEnoughLatencyTests
public boolean hasEnoughLatencyTests()Whether at least 3 latency samples have been collected.- Returns:
- true if we have at least 3 latency samples
needsExpeditedTest
public boolean needsExpeditedTest()Whether the tunnel needs an expedited test due to slow detection.- Returns:
- true if tunnel needs an expedited test due to slow detection
clearExpeditedTest
public void clearExpeditedTest()Clear the expedited test flag after running the expedited test.requestExpeditedTest
public void requestExpeditedTest()The tunnel appeared slow, so flag it for an expedited test.getTestStatus
The current test status of this tunnel for UI display.- Specified by:
getTestStatusin interfaceTunnelInfo- Returns:
- the current test status (UNTESTED, TESTING, GOOD, FAILING, or FAILED)
setTestStarted
public void setTestStarted()Called when a test is started.- Specified by:
setTestStartedin interfaceTunnelInfo
setTestFailed
public void setTestFailed()Called when a test fails. Updates the test status based on consecutive failure count. Only mark as FAILED after MAX_CONSECUTIVE_TEST_FAILURES (3) failures - before that, it's just FAILING and still counts as a valid tunnel.- Specified by:
setTestFailedin interfaceTunnelInfo
setTestFailing
public void setTestFailing()Mark the tunnel FAILING regardless of the hard-failure counter.setTestFailed()derives the status from_failures, so it reports GOOD for a tunnel retained on soft send timeouts alone — which would leave the tunnel selectable and hold its slot in the pool's good-tunnel accounting while it keeps timing out.- Specified by:
setTestFailingin interfaceTunnelInfo
setTestTooSlow
public void setTestTooSlow()Mark tunnel as scheduled for early expiry (pruned from pool). Revokes any last-chance admission — the pool decided to retire it.setTestOverBudget
public void setTestOverBudget()Mark tunnel as scheduled for early expiry due to pool being over budget. Revokes any last-chance admission — the pool decided to retire it.admitLastChance
Admit this tunnel for a last-chance test despite its remaining life being inside the early-expiry window. The deadline is snapshotted from the expiration at admission time so later pool state changes cannot extend it. Natural expiry still bounds it.- Parameters:
now- current wall-clock time (ms)reason- why the tunnel was admitted;nullclears
isLastChanceAdmitted
public boolean isLastChanceAdmitted(long now) Is a last-chance test admission still valid atnow? Only expiration shortens the window. The snapshot deadline prevents a re-read of a later expiration from extending it, andclearLastChanceAdmission()revokes it once the test settles.- Parameters:
now- current wall-clock time (ms)- Returns:
- true if an unexpired admission is in effect
getLastChanceReason
Why this tunnel was admitted for a last-chance test.- Returns:
- the reason, never null (
TunnelCreatorConfig.LastChanceReason.NONEwhen absent)
getLastChanceDeadline
public long getLastChanceDeadline()When the last-chance admission expires (deadline snapshot).- Returns:
- the deadline (ms), or 0 if never admitted
getLastChanceAdmission
public long getLastChanceAdmission()When the last-chance admission was granted (ms), or 0 if never.- Returns:
- the admission time in ms, 0 when never admitted
clearLastChanceAdmission
public void clearLastChanceAdmission()Revoke the last-chance admission (test settled, or no longer needed).getConsecutiveFailures
public int getConsecutiveFailures()The number of consecutive test failures.- Specified by:
getConsecutiveFailuresin interfaceTunnelInfo- Returns:
- the count of consecutive failures
setChaChaReplyKeys
The ECIES reply key and associated data for the given hop.- Parameters:
hop- the hop number, gateway is 0key- the reply keyad- the associated data
isEC
public boolean isEC(int hop) Is it an ECIES hop?- Parameters:
hop- the hop number, gateway is 0- Returns:
- whether e c
getChaChaReplyKey
The ECIES reply key for the given hop, or null.- Parameters:
hop- the hop number, gateway is 0- Returns:
- the cha cha reply key
getChaChaReplyAD
public byte[] getChaChaReplyAD(int hop) The ECIES reply associated data for the given hop, or null.- Parameters:
hop- the hop number, gateway is 0- Returns:
- the cha cha reply a d
setGarlicReplyKeys
ECIES short OBEP record only.- Parameters:
keys- the one time session carrying the short reply keys
getGarlicReplyKeys
ECIES short OBEP record only.- Returns:
- null for ElGamal or ECIES long record or non-OBEP
toString
toShortString
Compact one-line tunnel identifier for log output: role, client or exploratory, nickname and short destination. No hop list, no newlines.- Returns:
- the role, class, nickname and short destination, on one line
toStringFull
Render every hop, its peer, and its tunnel IDs, for a full description.It ends with the garlic reply key and tag, so DEBUG only - never log the result at INFO or above.
- Returns:
- the multi-line description, never null