- Direct Known Subclasses:
PeerState2
Public only for UI peers page. Not a public API, not for external use.
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static enumFast-retransmit recovery stage for a single message, by NACK count.(package private) static enumResult of classifying one outbound message during a finishAndAllocate() scan over _outboundMessages.Field Summary
Modifier and TypeFieldDescriptionprivate final SimpleBandwidthEstimatorEstimator of the peer's bandwidth.private longCached oldest message lifetime from the most recent finishAndAllocate() pass.private intCached count from the most recent finishAndAllocate() pass.private longHow far off is the remote peer from our clock, in milliseconds? A positive number means our clock is ahead of theirs.private final ObjectLock for the clock skew calculations.private intHow many concurrent outbound messages do we allow OutboundMessageFragments to send.private intHow many consecutive messages have we sent and not received an ACK to.private intHow many concurrency rejections have we had in a row.private longConsecutive small packets seen for MTU probing.protected final RouterContextThe router context.protected booleanHave we migrated away from this peer to another newer one?private final List<OutboundMessageState> Messages that failed, buffered for retry.private final AtomicBooleanTrue while a fast retransmit is pending.protected final ObjectLock for inbound operations.protected final ConcurrentMap<Long, InboundMessageState> List of InboundMessageState for active messages.protected final booleanIs it inbound?protected final longThe key establishment time.private intWhat is the largest packet we will ever send to the peer?protected longWhen did we last send ACKs to the peer?private longWhen congestion last occurred.private longLast time it was made an introducer.private longWhen did we last send them a ping?private longWhen did we last receive a packet from them?private longLast time we logged a send rejection (for rate-limited logging).private intLast 5% loss-ratio bucket reported to the profile, -1 = nothing reported yet.private longWhen did we last send them a message that was ACKed.private longWhen did we last send them a packet?protected final LogThe log.private final intMinimum transmitted packets before a loss ratio is reported, fromProfileOrganizer.PROP_LOSSY_MIN_PACKETS.private booleanTrue when the peer may be disconnected.private intMessages received from the peer.private final AtomicIntegerMessages sent to the peer.private final intSmallest MTU allowed for this peer.protected intWhat is the largest packet we can currently send to the peer?private intMTU decreases counted for this peer.private intMTU increases counted for this peer.private intThe MTU for receiving from the peer.private longNext outbound message sequence number.private final ObjectLock for outbound operations.private final CachedIteratorCollection<OutboundMessageState> Mostly messages that have been transmitted and are awaiting acknowledgement, although there could be some that have not been sent yet.private final PriBlockingQueue<OutboundMessageState> Priority queue of messages that have not yet been sent.private intPackets received from the peer.protected intHow many duplicate packets were received within the last RETRANSMISSION_PERIOD_WIDTH packets.private intHow many packets were retransmitted within the last RETRANSMISSION_PERIOD_WIDTH packets.private intPackets transmitted to the peer.private longWhen the path-unverified send-window growth freeze expires; 0 = not frozen.private intSmoothed receive rate, for display only.private intBytes received in the current period.private longWhen the receive period began.protected RemoteHostIdCached RemoteHostId, used to find the peerState by remote info.protected final byte[]What IP is the peer sending and receiving packets on?protected InetAddressCached IP address.protected final HashThe peer are we talking to.protected intWhat port is the peer sending and receiving packets on?private final AtomicLongWhen the retransmit timer is about to trigger.private intCurrent retransmission timeout.protected intCurrent round trip time estimate.private intSmoothed mean deviation in the RTT.private final AtomicIntegerHow many bytes should we send to the peer in a second.private intHow many bytes can we send to the peer in the current second.private final ObjectLock for the send window calculations.protected final StringSix-char base64 prefix of the remote peer hash, pre-computed for log messages (the full encode per log line was hot on floodfills).private intWhen sendWindowBytes is below this, grow the window size quickly, but after we reach it, grow it slowly.private final List<OutboundMessageState> Reusable lists for finishAndAllocate() — avoids per-volley allocation churn.private longIf they have offered to serve as an introducer to us, this is the tag we can use to publish that fact.protected final UDPTransportThe UDP transport.protected longWhen did we decide we need to ACK to this peer?private longIf we are serving as an introducer to them, this is the the tag that they can publish that, when presented to us, will cause us to send a relay introduction to the current peer.private static final AtomicIntegerHow frequently do we want to send ACKs to a peer? (dynamically tuned).private static final longAfter this time, we start adding backoff delay (5 seconds).(package private) static final longFloor on the gap between full congestion responses (ms).static final intDefault MTU.private static final intIf this many acks arrive out of order, fast rtx.private static intInitial concurrent messages per peer — configurable.private static intInitial RTO before first RTT sample — configurable viai2p.transport.udp.initRTO.private static final intInitial round trip time estimate.private static final intIPv6 packet overhead in bytes (IP + UDP + MAC + IV, 80).static final intIPv4 maximum MTU.private static intHard cap on concurrent messages per peer — adjustable via Tuner.(package private) static final intHard cap on partially-received inbound messages held per peer.static final intIPv6 maximum MTU.private static final longMaximum lifetime before a message is considered stuck and expired (60 seconds).static final intMax of IPv4 and IPv6 max MTUs.private static intMaximum retransmission timeout — configurable viai2p.transport.udp.maxRTO.private static intMax send window bytes — configurable viai2p.transport.udp.maxSendWindow.(package private) static final intHeap-scaled CWIN ceiling: 1MB minimum, up to 16MB, roughly 1MB per 256MB of heap.private static final intThis is room for three explicit acks or two partial acks or one of each = 13.private static intThe minimum number of outstanding messages (NOT fragments/packets) — configurable.private static final intAlways leave room for this many explicit acks.static final intIPv6 minimum MTU.static final intIPv4 minimum MTU.private static intMinimum retransmission timeout in milliseconds, configurable via "i2p.transport.udp.minRTO" and clamped to [100, 2000].private static final intReceive MTU change shown in the log.private static final intAmount to adjust up or down inadjustMTU(int, boolean)- should be multiple of 16, at least for SSU 1.private static intOutbound message queue depth per peer, -1 = use router config.private static final intIPv4 packet overhead in bytes (IP + UDP + MAC + IV, 60).(package private) static final longHow long send-window growth stays frozen after a path-unverified migration signal (ms).private static intNumber of MTUs to restart the send window at after an RTO-timeout collapse.private static final intWhen RTT > TARGET_RTT but there are queued messages, increase modestly.private static final longInterval between rejection log messages.(package private) static final longHow many packets will be considered within the retransmission rate calculation.private static final longFailsafe push of the retransmit timer when a retransmit pass selected nothing.private static final floatThis is the value specified in RFC 2988.private static intRTT multiplier above which we multiplicative-decrease concurrency.private static intTarget RTT in ms — below this, increase concurrency; above this, decrease.Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedPeerState(RouterContext ctx, UDPTransport transport, InetSocketAddress addr, Hash remotePeer, boolean isInbound, int rtt) For SSU2.Method Summary
Modifier and TypeMethodDescriptionprotected booleanAn ACK of a fragment was received.(package private) voidadd(OutboundMessageState state) Add an outbound message state to the queue.(package private) voidadjustClockSkew(long skew) Update the moving-average clock skew based on the current difference.private voidadjustMTU(int maxPktSz, boolean success) Adjust upward if a large packet was successfully sent without retransmission.private booleanallocateSendingBytes(OutboundMessageState state, long now) Decrement the remaining bytes in the current period's window, returning true if the full size can be decremented, false if it cannot.(package private) static intcappedRefund(int remaining, int refund, int windowBytes) Refundrefundbytes into the send-window remaining budget, capped at the window size (never let the remaining budget exceed the congestion window, per RFC 5681).(package private) voidchangePort(int newPort) Change the remote port.(package private) static PeerState.OutcomeclassifyOutcome(boolean complete, boolean expired, boolean overSent) Per-message outcome in a finishAndAllocate() scan, computed once per message so the scan loop stays a thin dispatcher.(package private) voidAll acks have been sent - SSU 1 only, see override.(package private) static booleancongestionCooldownElapsed(long last, long now, int rto) Whether enough time has elapsed since the last congestion response to allow another one.private voidEither they told us to back off, or we had to resend to get the data through.(package private) voidSame as setLastReceivedTime(now).(package private) voidDrop all outbound messages.static inteffectiveRTO(int rto, int minRto, int maxRto) Clamp a raw RTO estimate into the active [minRto, maxRto] window.(package private) static InboundMessageStateevictInboundMessage(ConcurrentMap<Long, InboundMessageState> inbound) Make room for one more partially-received inbound message.private voidLeave fast retransmit mode if we were in it, and adjust SST and window variables accordingly.(package private) intExpire partially received inbound messages, returning how many are still pending.(package private) static PeerState.FastRtxModefastRtxMode(int nacks) Fast-retransmit progression as a function of the NACK count for a single message.(package private) List<OutboundMessageState> finishAndAllocate(long now) Replaces the two-pass pattern of finishMessages() + allocateSend() with a single pass through _outboundMessages.(package private) intPacket overhead plus room for acks.(package private) intHow much payload data can we shove in there?static intCurrent ACK frequency.static long[]getAggregateStats(Collection<PeerState> peers) Compute aggregate transport stats across all peers for tuner visibility.longClock skew.static intClock skew fudge factor.intConcurrent sends count.intConcurrent send window.intConsecutive failed sends count.intConsecutive send rejections count.longTime since the peer was last heard from or sent to fully.(package private) Map<Long, InboundMessageState> Fetch the internal id (Long) to InboundMessageState for incomplete inbound messages.static intConcurrent messages a new peer starts with.static intInitial RTO for new peers.(package private) longLast introducer time.longWhen the cipher and MAC keys were established.longWhen we last sent an ACK.longLast receive time.longLast send fully time.(package private) longLatest of last sent, last ACK, last ping.longLast send time.static intMax concurrent messages per peer.static intMaximum RTO ceiling.static intMax send window (CWIN).static intThe heap-scaled CWIN ceiling, for use by the Tuner's MaxSendWindowParam (max range must match the clamp applied insetMaxSendWindow(int)).booleanWhether we may disconnect.intI2NP messages received.intI2NP messages sent - does not include duplicates.static intConcurrent messages a degraded peer is limited to.static intMinimum RTO floor.intgetMTU()Maximum transmission unit.(package private) intgetNextDelay(long now) Uses cached oldest lifetime from the most recent finishAndAllocate() pass.intOutbound message count.static longBridge to OutboundMessageState.getMessageExpiration for Tuner (different package).static intgetOutboundQueueSize(RouterContext ctx, int def) Outbound message queue depth per peer.intPackets received count.intPackets received duplicate count.intPackets retransmitted count.intPackets transmitted count.static intPost-RTO-collapse window restart size.intgetReceiveBps(long now) Receive Bps estimate.intReceive MTU estimate.Remote host ID.byte[]Remote IP address bytes.Cached remote IP address.Remote peer hash.intRemote port.intgetRTO()Retransmission timeout.intgetRTT()Round trip time.intRTT deviation.intgetSendBps(long now) The Westwood+ bandwidth estimate.intSend window bytes.intSend window bytes remaining.static longBridge to PeerState2.sentMessagesCleanTime for Tuner (different package).intSlow start threshold.longTag they relay to us as.(package private) UDPTransportConvenience for OutboundMessageState so it can fail itself.intPeer SSU version.longTag we relay to them as.private booleanhandleFailed(List<OutboundMessageState> failed, int failedSize, int failedCount, boolean totalFail, boolean shouldLogInfo, boolean shouldLogWarn) Process failed outbound messages and their side effects, completely outside _outboundLock.(package private) booleanAfter a finishAndAllocate() pass, reports whether any outbound messages remain.(package private) booleanhighestSeqNumAcked(long highest) Enter or leave fast retransmit mode, and adjust SST and window variables accordingly.(package private) intIncrement consecutive failed sends.booleanWhether the peer is dead or its outbound queue is backlogged.booleanWhether this is an inbound connection.booleanisIPv6()Whether the connection uses IPv6.(package private) static booleanisTotalFail(OutNetMessage msg, boolean isInbound, long seqNum) Whether a failed outbound message counts as a total-first-message failure.static voidloadConfig(RouterContext ctx) Load configurable UDP transport parameters fromrouter.config.(package private) voidTransfer the basic activity/state from the old peer to the current peerprivate voidlocked_messageACKed(int bytesACKed, int maxPktSz, long lifetime, int numSends, boolean anyPending, boolean anyQueued) We sent a message which was ACKed containing the given # of bytes.private booleanlocked_shouldSend(OutboundMessageState state, long now) Locks this.private voidmessageACKed(int bytesACKed, int maxPktSz, long lifetime, int numSends, boolean anyPending, boolean anyQueued) We sent a message which was ACKed containing the given # of bytes.(package private) voidmessageFullyReceived(Long messageId, int bytes) We received the message specified completely.(package private) voidWe received a partial message, or we want to send some acks.protected voidmessagePartiallyReceived(long now) We received a partial message, or we want to send some acks.(package private) voidmessageRetransmitted(int packets, int maxPktSz) Handle a message retransmission.(package private) static booleanmtuDecreaseEligible(int mtu, int minMTU, int maxPktSz) Whether the MTU should be reduced after a lossy transmission.(package private) static booleanmtuIncreaseEligible(int mtu, int largeMTU, int maxPktSz, int mtuDecreases, int randomInt) Whether a larger MTU is eligible after a clean transmission.(package private) static intnewlyAckedBytes(int unackedBefore, boolean complete, int unackedAfter) Compute the bytes newly confirmed by one incoming ACK for a single message: the full previously-unacked size when the message just became complete, otherwise only the delta newly covered by this ACK.(package private) static intnextConcurrentLimit(int numSends, int rtt, int current, int queued, int randomInt) Compute the next concurrent-messages limit after an ACK, pure so the AIMD tuning policy is unit-testable.(package private) static intnextCongestionRTO(int currentRTO, int rtt, int rttDeviation, int minRTO, int maxRTO) Compute the RTO to apply after a congestion signal.(package private) voidpacketReceived(int size) Record a received packet.(package private) voidpacketsTransmitted(int packets) Record that packets were transmitted.(package private) voidHold send-window growth while the path is unverified (SSU2 connection migration,limitSending).(package private) static booleanpathUnverifiedBlocksGrowth(long now, long pathUnverifiedUntil) Whether send-window growth must be held because the path is unverified (SSU2 connection migration).(package private) voidClear the path-unverified growth freeze (migration completed, failed, or cancelled — the current path is again the verified one).(package private) static booleanreachedRetransmitCap(int rvSize, int sizeBefore, boolean fastRetransmit) Whether a retransmit-mode scan has accumulated enough messages to stop.private voidrecalculateTimeouts(long lifetime) Adjust the tcp-esque timeouts.private voidReport the current retransmit ratio to the profile when it crosses a 5% bucket boundary since the last report.(package private) static longretransmitFireTime(boolean firstArming, boolean fastRetransmit, long now, long rto) Decide the next retransmit-timer fire time after a volley.static voidsetAckFrequency(int freq) ACK frequency.(package private) voidsetHisMTU(int mtu) Remote peer's MTU.static voidsetInitConcurrentMsgs(int msgs) Initial concurrent messages per peer (called by Tuner).static voidsetInitRTO(int ms) Initial RTO for new peers (called by Tuner).(package private) voidRecord the last time we used them as an introducer.(package private) voidsetLastPingTime(long when) Last ping time.(package private) voidsetLastReceiveTime(long when) Last receive time.(package private) voidsetLastSendTime(long when) Last send time.static voidsetMaxConcurrentMessages(int max) Max concurrent messages per peer (called by Tuner).static voidsetMaxRTO(int ms) Maximum RTO ceiling (called by Tuner).static voidsetMaxSendWindow(int bytes) Max send window / CWIN (called by Tuner).voidMay disconnect to true.static voidsetMinConcurrentMsgs(int msgs) Minimum concurrent messages per peer (called by Tuner).static voidsetMinRTO(int ms) Minimum RTO floor (called by Tuner).static voidsetOutboundMsgExpiration(long ms) Bridge to OutboundMessageState.setMessageExpiration for Tuner (different package).static voidsetOutboundQueueSize(int size) Outbound message queue depth per peer (called by Tuner).static voidsetPostRTOWindowMTUs(int mtus) Send-window restart size after an RTO-timeout collapse (called by Tuner).static voidsetSentMessagesCleanTime(long ms) Bridge to PeerState2.setSentMessagesCleanTime for Tuner (different package).(package private) voidsetTheyRelayToUsAs(long tag) If they have offered to serve as an introducer to us, this is the tag we can use to publish that fact.(package private) voidsetWeRelayToThemAs(long tag) If we are serving as an introducer to them, this is the the tag that they can publish that, when presented to us, will cause us to send a relay introduction to the current peer.(package private) static booleanshouldGrowSendWindow(int sendWindow, int slowStartThreshold, int bytesACKed, float randomFloat) Whether an ACK should grow the send window.protected booleanSSU 2 only.(package private) static booleanshouldSkipFastRetransmit(boolean fastRetransmit, int nacks) Whether to skip a message during a retransmit-mode scan.(package private) StringCompact one-line peer identifier for log output: short hash, direction, version and remote host id.toString()(package private) static booleanwantLargerMTU(boolean success, int packetsTransmitted, int packetsRetransmitted) Whether a near-lossless transmission history warrants probing a larger MTU.
Field Details
_context
The router context._log
The log._remotePeer
The peer are we talking to. This should be set as soon as this state is created if we are initiating a connection, but if we are receiving the connection this will be set only after the connection is established._shortHash
Six-char base64 prefix of the remote peer hash, pre-computed for log messages (the full encode per log line was hot on floodfills)._keyEstablishedTime
protected final long _keyEstablishedTimeThe key establishment time._clockSkew
private long _clockSkewHow far off is the remote peer from our clock, in milliseconds? A positive number means our clock is ahead of theirs._clockSkewLock
Lock for the clock skew calculations._lastSendTime
private long _lastSendTimeWhen did we last send them a packet?_lastSendFullyTime
private volatile long _lastSendFullyTimeWhen did we last send them a message that was ACKed._lastPingTime
private long _lastPingTimeWhen did we last send them a ping?_lastReceiveTime
private volatile long _lastReceiveTimeWhen did we last receive a packet from them?_consecutiveFailedSends
private volatile int _consecutiveFailedSendsHow many consecutive messages have we sent and not received an ACK to._lastACKSend
protected volatile long _lastACKSendWhen did we last send ACKs to the peer?_wantACKSendSince
protected volatile long _wantACKSendSinceWhen did we decide we need to ACK to this peer?_sendWindowBytes
How many bytes should we send to the peer in a second._sendWindowBytesRemaining
private volatile int _sendWindowBytesRemainingHow many bytes can we send to the peer in the current second._sendWindowBytesRemainingLock
Lock for the send window calculations._bwEstimator
Estimator of the peer's bandwidth._receiveBps
private int _receiveBpsSmoothed receive rate, for display only._receiveBytes
private int _receiveBytesBytes received in the current period._receivePeriodBegin
private long _receivePeriodBeginWhen the receive period began._lastCongestionOccurred
private volatile long _lastCongestionOccurredWhen congestion last occurred._pathUnverifiedUntil
private volatile long _pathUnverifiedUntilWhen the path-unverified send-window growth freeze expires; 0 = not frozen._slowStartThreshold
private volatile int _slowStartThresholdWhen sendWindowBytes is below this, grow the window size quickly, but after we reach it, grow it slowly._remoteIP
protected final byte[] _remoteIPWhat IP is the peer sending and receiving packets on?_remoteIPAddress
Cached IP address._remotePort
protected volatile int _remotePortWhat port is the peer sending and receiving packets on?_remoteHostId
Cached RemoteHostId, used to find the peerState by remote info._weRelayToThemAs
private long _weRelayToThemAsIf we are serving as an introducer to them, this is the the tag that they can publish that, when presented to us, will cause us to send a relay introduction to the current peer._theyRelayToUsAs
private long _theyRelayToUsAsIf they have offered to serve as an introducer to us, this is the tag we can use to publish that fact._mtu
protected volatile int _mtuWhat is the largest packet we can currently send to the peer?_mtuReceive
private int _mtuReceiveThe MTU for receiving from the peer._largeMTU
private int _largeMTUWhat is the largest packet we will ever send to the peer?_minMTU
private final int _minMTUSmallest MTU allowed for this peer._consecutiveSmall
private long _consecutiveSmallConsecutive small packets seen for MTU probing._mtuIncreases
private int _mtuIncreasesMTU increases counted for this peer._mtuDecreases
private int _mtuDecreasesMTU decreases counted for this peer._rtt
protected volatile int _rttCurrent round trip time estimate._rttDeviation
private volatile int _rttDeviationSmoothed mean deviation in the RTT._rto
private volatile int _rtoCurrent retransmission timeout.RETRANSMISSION_PERIOD_WIDTH
static final long RETRANSMISSION_PERIOD_WIDTHHow many packets will be considered within the retransmission rate calculation._messagesReceived
private int _messagesReceivedMessages received from the peer._messagesSent
Messages sent to the peer._lastRejectionLogTime
private long _lastRejectionLogTimeLast time we logged a send rejection (for rate-limited logging).REJECTION_LOG_INTERVAL
private static final long REJECTION_LOG_INTERVALInterval between rejection log messages.- See Also:
_packetsTransmitted
private int _packetsTransmittedPackets transmitted to the peer._packetsRetransmitted
private int _packetsRetransmittedHow many packets were retransmitted within the last RETRANSMISSION_PERIOD_WIDTH packets._lastReportedLossBucket
private int _lastReportedLossBucketLast 5% loss-ratio bucket reported to the profile, -1 = nothing reported yet. Lock: _outboundLock._lossyMinPackets
private final int _lossyMinPacketsMinimum transmitted packets before a loss ratio is reported, fromProfileOrganizer.PROP_LOSSY_MIN_PACKETS. Read once per peer rather than per volley:reportLossRatio()is called under _outboundLock, and a property lookup there falls through to System.getProperty every time. A peer reads it once at construction, which is off the hot path._nextSequenceNumber
private long _nextSequenceNumberNext outbound message sequence number._fastRetransmit
True while a fast retransmit is pending._packetsReceivedDuplicate
protected volatile int _packetsReceivedDuplicateHow many duplicate packets were received within the last RETRANSMISSION_PERIOD_WIDTH packets._packetsReceived
private int _packetsReceivedPackets received from the peer._mayDisconnect
private volatile boolean _mayDisconnectTrue when the peer may be disconnected._inboundMessages
List of InboundMessageState for active messages._outboundMessages
Mostly messages that have been transmitted and are awaiting acknowledgement, although there could be some that have not been sent yet._outboundQueue
Priority queue of messages that have not yet been sent. They are taken from here and put in _outboundMessages._retransmitTimer
When the retransmit timer is about to trigger._transport
The UDP transport._dead
protected volatile boolean _deadHave we migrated away from this peer to another newer one?MIN_CONCURRENT_MSGS
private static volatile int MIN_CONCURRENT_MSGSThe minimum number of outstanding messages (NOT fragments/packets) — configurable.MAX_MESSAGE_LIFETIME
private static final long MAX_MESSAGE_LIFETIMEMaximum lifetime before a message is considered stuck and expired (60 seconds).- See Also:
MAX_INBOUND_MESSAGES
static final int MAX_INBOUND_MESSAGESHard cap on partially-received inbound messages held per peer. Each entry owns pooled fragment buffers of up toUDPPacket.MAX_PACKET_SIZE, and a peer that sends one fragment per distinct message ID never trips the same-ID expiry branch, so without a cap the map grows for the life of the connection.- See Also:
BACKOFF_START_LIFETIME
private static final long BACKOFF_START_LIFETIMEAfter this time, we start adding backoff delay (5 seconds).- See Also:
INIT_CONCURRENT_MSGS
private static volatile int INIT_CONCURRENT_MSGSInitial concurrent messages per peer — configurable.MAX_CONCURRENT_MSGS
private static volatile int MAX_CONCURRENT_MSGSHard cap on concurrent messages per peer — adjustable via Tuner.TARGET_RTT
private static volatile int TARGET_RTTTarget RTT in ms — below this, increase concurrency; above this, decrease. I2P network RTT through 2-4 hops is typically 500-2000ms. High enough to avoid false congestion signals from normal network latency. Configurable viai2p.transport.udp.targetRTT.RTT_DECREASE_FACTOR
private static volatile int RTT_DECREASE_FACTORRTT multiplier above which we multiplicative-decrease concurrency. Only decrease when RTT > TARGET_RTT * RTT_DECREASE_FACTOR — truly congested. Configurable viai2p.transport.udp.rttDecreaseFactor.QUEUE_BACKPRESSURE_INCREASE
private static final int QUEUE_BACKPRESSURE_INCREASEWhen RTT > TARGET_RTT but there are queued messages, increase modestly.- See Also:
_concurrentMessagesAllowed
private int _concurrentMessagesAllowedHow many concurrent outbound messages do we allow OutboundMessageFragments to send. This counts full messages, NOT fragments (UDP packets). Dynamically adjusted based on measured RTT: increased when RTT < TARGET_RTT, decreased when RTT > TARGET_RTT * RTT_DECREASE_FACTOR._consecutiveRejections
private int _consecutiveRejectionsHow many concurrency rejections have we had in a row._isInbound
protected final boolean _isInboundIs it inbound?_lastIntroducerTime
private long _lastIntroducerTimeLast time it was made an introducer.MAX_SEND_WINDOW_BYTES
private static volatile int MAX_SEND_WINDOW_BYTESMax send window bytes — configurable viai2p.transport.udp.maxSendWindow.MAX_SEND_WINDOW_CEILING
static final int MAX_SEND_WINDOW_CEILINGHeap-scaled CWIN ceiling: 1MB minimum, up to 16MB, roughly 1MB per 256MB of heap. Replaces the fixed 1MB cap that clamped tuner growth and kept high-memory routers below 1MB/s throughput (0.9.70+), and doubled from heap/512 to heap/256 in 0.9.71+ so a 4GB router can reach the streaming ceiling (~8 MB/s) instead of topping out at 2MB/s.DEFAULT_MTU
MIN_MTU
public static final int MIN_MTUIPv4 minimum MTU.Sized so a 1044 byte tunnel data message still fits in two packets: that needs 522 fragment bytes each, plus 46 for SSU, 20 for IP and 8 for UDP, giving 596. This leaves headroom above that floor (the smallest value meeting the floor and the alignment rule below would be 604) because the ACK allowance has to fit as well.
The IPv4 IP and UDP headers are 28 bytes, so the SSU payload area is 620 - 28 = 592, which is 37 whole 16-byte blocks.
PacketBuilder2.buildPacket(OutboundMessageState, int, PeerState2)requires that alignment for its padding.ACKs also have to fit, especially 1 + (4 * MAX_RESEND_ACKS_SMALL), so the max acks are reduced when the small MTU is in use. That is a best effort: a 2646 byte maximum-size message needs about 5 fragments at this MTU (2646 / (620 - 87)), which the small-MTU ACK allowance does not cover.
- See Also:
MIN_IPV6_MTU
public static final int MIN_IPV6_MTUIPv6 minimum MTU. The IPv6 IP and UDP headers are 48 bytes, so 1280 - 48 = 1232, which is 77 whole 16-byte blocks.- See Also:
MAX_IPV6_MTU
public static final int MAX_IPV6_MTUIPv6 maximum MTU. 1488 - 48 = 1440, which is 90 whole 16-byte blocks, so it satisfies the same payload alignment asMIN_IPV6_MTU.- See Also:
LARGE_MTU
public static final int LARGE_MTUIPv4 maximum MTU.The size is set by two constraints.
First, 1480 bytes are needed to carry a maximum-size I2NP message as two fragments: 2646 / 2 = 1323 data bytes each, plus 157 bytes of per-packet SSU and datagram overhead (74 + 46 + 1 + 4 * 9, the last term covering the fragment block header and four nine-byte ACK allowances).
Second, the IPv4 IP and UDP headers are 28 bytes, so the SSU payload area must be a whole number of 16-byte blocks for
PacketBuilder2.buildPacket(OutboundMessageState, int, PeerState2)to pad correctly. 1480 would leave 1452 bytes, which is not a multiple of 16; the next aligned size is 1484 - 28 = 1456 = 91 * 16. 1484 is therefore the smallest value that meets both constraints.Measurements put most small I2NP messages well below this; messages of 1900 to 4500 bytes do not fit any live network MTU anyway.
- See Also:
MAX_MTU
public static final int MAX_MTUMax of IPv4 and IPv6 max MTUs.MTU_STEP
private static final int MTU_STEPAmount to adjust up or down inadjustMTU(int, boolean)- should be multiple of 16, at least for SSU 1.- See Also:
MIN_RTO
private static volatile int MIN_RTOMinimum retransmission timeout in milliseconds, configurable via "i2p.transport.udp.minRTO" and clamped to [100, 2000].INIT_RTO
private static volatile int INIT_RTOInitial RTO before first RTT sample — configurable viai2p.transport.udp.initRTO.INIT_RTT
MAX_RTO
private static volatile int MAX_RTOMaximum retransmission timeout — configurable viai2p.transport.udp.maxRTO.POST_RTO_WINDOW_MTUS
private static volatile int POST_RTO_WINDOW_MTUSNumber of MTUs to restart the send window at after an RTO-timeout collapse. 1 = RFC 5681 loss window (one packet, the conservative default). Higher values speed slow-start recovery for bulk peers at the cost of more in-flight bytes immediately after loss. Tuned via Tuner.CONGESTION_COOLDOWN_MIN_MS
static final long CONGESTION_COOLDOWN_MIN_MSFloor on the gap between full congestion responses (ms). Congestion cooldown used to track_rto, which the death-spiral fix pulled from tens of seconds down to ~1s — allowing a window collapse every second under sustained loss. Real congestion still usesmax(rto, this); migration never reaches this path.- See Also:
PATH_UNVERIFIED_FREEZE_MS
static final long PATH_UNVERIFIED_FREEZE_MSHow long send-window growth stays frozen after a path-unverified migration signal (ms). Refreshed while the path remains unverified; cleared bypathVerified()when migration ends.- See Also:
OUTBOUND_QUEUE_SIZE
private static volatile int OUTBOUND_QUEUE_SIZEOutbound message queue depth per peer, -1 = use router config. Set by the Tuner when autotuningrouter.peerOutboundQueueSize.ACK_FREQUENCY
How frequently do we want to send ACKs to a peer? (dynamically tuned).FAST_RTX_ACKS
private static final int FAST_RTX_ACKSIf this many acks arrive out of order, fast rtx.- See Also:
_outboundLock
Lock for outbound operations._inboundLock
Lock for inbound operations._succeededBuffer
Reusable lists for finishAndAllocate() — avoids per-volley allocation churn._failedBuffer
Messages that failed, buffered for retry._cachedOutboundCount
private volatile int _cachedOutboundCountCached count from the most recent finishAndAllocate() pass. Used by getNextVolley() to determine if a peer has messages._cachedOldestLifetime
private volatile long _cachedOldestLifetimeCached oldest message lifetime from the most recent finishAndAllocate() pass. Updated during the finishAndAllocate() iteration across _outboundMessages.RETRANSMIT_FAILSAFE_MS
private static final long RETRANSMIT_FAILSAFE_MSFailsafe push of the retransmit timer when a retransmit pass selected nothing.- See Also:
RTT_DAMPENING
private static final float RTT_DAMPENINGThis is the value specified in RFC 2988.- See Also:
MTU_RCV_DISPLAY_THRESHOLD
private static final int MTU_RCV_DISPLAY_THRESHOLDReceive MTU change shown in the log.- See Also:
OVERHEAD_SIZE
private static final int OVERHEAD_SIZEIPv4 packet overhead in bytes (IP + UDP + MAC + IV, 60).- See Also:
IPV6_OVERHEAD_SIZE
private static final int IPV6_OVERHEAD_SIZEIPv6 packet overhead in bytes (IP + UDP + MAC + IV, 80).- See Also:
MIN_EXPLICIT_ACKS
private static final int MIN_EXPLICIT_ACKSAlways leave room for this many explicit acks. Only for data packets. Does not affect ack-only packets. This directly affects data packet overhead, adjust with care.- See Also:
MIN_ACK_SIZE
private static final int MIN_ACK_SIZEThis is room for three explicit acks or two partial acks or one of each = 13.- See Also:
Constructor Details
PeerState
protected PeerState(RouterContext ctx, UDPTransport transport, InetSocketAddress addr, Hash remotePeer, boolean isInbound, int rtt) For SSU2.- Parameters:
ctx- the router context, supplying the log manager and tunablestransport- the UDP transport that owns this peer state and can drop the peeraddr- the remote socket address; its IP bytes and port seed _remoteIP and _remotePortremotePeer- the peer's RouterIdentity hashisInbound- true when the peer dialed us, false when we dialed the peerrtt- the round trip time in ms, or 0 when unmeasured, leaving the initial RTO in place
Method Details
getMaxConcurrentMessages
public static int getMaxConcurrentMessages()Max concurrent messages per peer.- Returns:
- the current max concurrent messages per peer
setMaxConcurrentMessages
public static void setMaxConcurrentMessages(int max) Max concurrent messages per peer (called by Tuner). Scales with available RAM: ~1/4 of RAM in MB, clamped 256-4096.- Parameters:
max- the max concurrent messages to set
getSentMessagesCleanTime
public static long getSentMessagesCleanTime()Bridge to PeerState2.sentMessagesCleanTime for Tuner (different package).- Returns:
- the sent messages clean time
setSentMessagesCleanTime
public static void setSentMessagesCleanTime(long ms) Bridge to PeerState2.setSentMessagesCleanTime for Tuner (different package).- Parameters:
ms- the clean time in ms
getOutboundMsgExpiration
public static long getOutboundMsgExpiration()Bridge to OutboundMessageState.getMessageExpiration for Tuner (different package).- Returns:
- the outbound message expiration
setOutboundMsgExpiration
public static void setOutboundMsgExpiration(long ms) Bridge to OutboundMessageState.setMessageExpiration for Tuner (different package).- Parameters:
ms- the expiration in ms
loadConfig
Load configurable UDP transport parameters fromrouter.config. Called once during UDPTransport initialization.- Parameters:
ctx- router context for property access
getAggregateStats
Compute aggregate transport stats across all peers for tuner visibility. Called periodically fromOutboundMessageFragments.- Parameters:
peers- collection of active peer states- Returns:
- array: [avgSendWindow, avgRTO, avgConcurrentMsgs, avgEffectiveRTO], or null if no peers. Index 1 is the raw per-peer estimate (the historical series, unchanged for existing readers); index 3 is the clamped [MIN_RTO, MAX_RTO] value each peer actually uses to schedule retransmits, so the two can be compared.
setOutboundQueueSize
public static void setOutboundQueueSize(int size) Outbound message queue depth per peer (called by Tuner).- Parameters:
size- queue depth; the Tuner clamps to 50-1000 before calling
getOutboundQueueSize
Outbound message queue depth per peer.- Parameters:
ctx- router context for config fallback when untuneddef- fallback default when neither tuned nor configured- Returns:
- the queue depth to use
getAckFrequency
public static int getAckFrequency()Current ACK frequency.- Returns:
- seconds between ACKs to a peer, dynamically tuned
setAckFrequency
public static void setAckFrequency(int freq) ACK frequency.- Parameters:
freq- new ACK frequency (bounded 50-300)
setInitRTO
public static void setInitRTO(int ms) Initial RTO for new peers (called by Tuner).- Parameters:
ms- initial RTO in ms, clamped 250-2000
setMinRTO
public static void setMinRTO(int ms) Minimum RTO floor (called by Tuner). Floor is 100 so the Tuner's death-spiral cut is effective;recalculateTimeouts(long)still uses max(MIN_RTO, RTT-based estimate).- Parameters:
ms- minimum RTO in ms, clamped 100-2000
setMaxRTO
public static void setMaxRTO(int ms) Maximum RTO ceiling (called by Tuner). Floor is 3000 so the Tuner's death-spiral cut is effective; default remains 60s for high-RTT paths until autotune tightens it.- Parameters:
ms- maximum RTO in ms, clamped 3000-120000
setMaxSendWindow
public static void setMaxSendWindow(int bytes) Max send window / CWIN (called by Tuner).- Parameters:
bytes- max send window in bytes, clamped 32KB to heap-scaled ceiling
getPostRTOWindowMTUs
public static int getPostRTOWindowMTUs()Post-RTO-collapse window restart size.- Returns:
- the post-RTO-collapse window restart size, in MTUs
setPostRTOWindowMTUs
public static void setPostRTOWindowMTUs(int mtus) Send-window restart size after an RTO-timeout collapse (called by Tuner).- Parameters:
mtus- number of MTUs, clamped 1-4 (1 = RFC 5681 loss window)
setInitConcurrentMsgs
public static void setInitConcurrentMsgs(int msgs) Initial concurrent messages per peer (called by Tuner).- Parameters:
msgs- initial concurrent messages, clamped 16-256
setMinConcurrentMsgs
public static void setMinConcurrentMsgs(int msgs) Minimum concurrent messages per peer (called by Tuner).- Parameters:
msgs- minimum concurrent messages, clamped 8-128
getInitRTO
public static int getInitRTO()Initial RTO for new peers.- Returns:
- the initial RTO for new peers in ms
getMinRTO
public static int getMinRTO()Minimum RTO floor.- Returns:
- the minimum RTO floor in ms
getMaxRTO
public static int getMaxRTO()Maximum RTO ceiling.- Returns:
- the maximum RTO ceiling in ms
getMaxSendWindow
public static int getMaxSendWindow()Max send window (CWIN).- Returns:
- the max send window (CWIN) in bytes
getMaxSendWindowCeiling
public static int getMaxSendWindowCeiling()The heap-scaled CWIN ceiling, for use by the Tuner's MaxSendWindowParam (max range must match the clamp applied insetMaxSendWindow(int)).- Returns:
- the CWIN ceiling in bytes
getInitConcurrentMsgs
public static int getInitConcurrentMsgs()Concurrent messages a new peer starts with.- Returns:
- the initial window, in messages
getMinConcurrentMsgs
public static int getMinConcurrentMsgs()Concurrent messages a degraded peer is limited to.- Returns:
- the minimum window, in messages
getClockSkewFudge
public static int getClockSkewFudge()Clock skew fudge factor.- Returns:
- clock skew fudge derived from current ACK frequency
classifyOutcome
Per-message outcome in a finishAndAllocate() scan, computed once per message so the scan loop stays a thin dispatcher. Precedence: COMPLETE > EXPIRED > OVER_SENT > SENDABLE - an expired message is reported as EXPIRED even when it also exceeded the volley cap, keeping the expire/aggressive stats distinct.- Parameters:
complete- the message finished (all fragments acked)expired- the message's expiry passedoverSent- the message exceededOutboundMessageFragments.MAX_VOLLEYS- Returns:
- the dominated outcome
retransmitFireTime
static long retransmitFireTime(boolean firstArming, boolean fastRetransmit, long now, long rto) Decide the next retransmit-timer fire time after a volley. A new timer is armed on first arming or while fast retransmit is active; otherwise the existing timer is left alone. Pure so the RTO policy is unit-testable.- Parameters:
firstArming- true if no retransmit timer is currently armedfastRetransmit- whether fast retransmit is activenow- the current clock reading in millisecondsrto- the current smoothed retransmit timeout- Returns:
- the fire time to arm, or -1L to leave the timer unchanged
shouldSkipFastRetransmit
static boolean shouldSkipFastRetransmit(boolean fastRetransmit, int nacks) Whether to skip a message during a retransmit-mode scan. During fast retransmit, messages that have not yet accumulatedFAST_RTX_ACKSNACKs are spared — they were not implicated in the loss and resending them would merely amplify congestion (RFC 5681 sec. 4.2). Pure so the scan loop gate is unit-testable.- Parameters:
fastRetransmit- whether fast retransmit is currently activenacks- the message's current NACK count- Returns:
- true to leave the message alone during this pass
reachedRetransmitCap
static boolean reachedRetransmitCap(int rvSize, int sizeBefore, boolean fastRetransmit) Whether a retransmit-mode scan has accumulated enough messages to stop. Caps each pass at half of the pre-cleanup active set unless fast retransmit is active (which deliberately floods the tail to trigger duplicate ACKs, RFC 5681 sec. 4.2). Pure so the scan cap is unit-testable.- Parameters:
rvSize- how many messages the current pass has selectedsizeBefore- the active-message count before this passfastRetransmit- whether fast retransmit is currently active- Returns:
- true when the pass should stop selecting
isTotalFail
Whether a failed outbound message counts as a total-first-message failure. Only the first outbound message (sequence number 0) of an outbound connection can destroy the peer. Failures of messages sent to an inbound peer are never total. Pure so the destroy decision is unit-testable.- Parameters:
msg- the failed message wrapper, may be nullisInbound- whether this PeerState is the inbound sideseqNum- the message's sequence number- Returns:
- true if this failure should destroy the peer
finishAndAllocate
Replaces the two-pass pattern of finishMessages() + allocateSend() with a single pass through _outboundMessages. Cleans up completed/expired messages and selects messages to send in one iteration.Sets _cachedOutboundCount for hasOutbound() and _cachedOldestLifetime for getNextDelay(). Does NOT scan _outboundQueue for oldest start time — the _outboundMessages iteration is sufficient for the delay heuristic, avoiding per-volley PriorityBlockingQueue iterator allocation.
- Parameters:
now- the current clock reading in milliseconds, used to age messages out of the queue- Returns:
- messages to send, or null if none ready
cappedRefund
static int cappedRefund(int remaining, int refund, int windowBytes) Refundrefundbytes into the send-window remaining budget, capped at the window size (never let the remaining budget exceed the congestion window, per RFC 5681). Pure so the refund bookkeeping is unit-testable.- Parameters:
remaining- the current_sendWindowBytesRemainingrefund- the byte count to add back (failed sends, freed blocks)windowBytes- the current_sendWindowBytes- Returns:
- the capped new remaining budget
handleFailed
private boolean handleFailed(List<OutboundMessageState> failed, int failedSize, int failedCount, boolean totalFail, boolean shouldLogInfo, boolean shouldLogWarn) Process failed outbound messages and their side effects, completely outside _outboundLock. Window bytes for unacked fragments are refunded under _sendWindowBytesRemainingLock (capped at the full window). A total failure of the first outbound message destroys the peer with REASON_FRAME_TIMEOUT and drops it.Logging is suppressed for banlisted peers.
- Parameters:
failed- the collected failed states, never emptyfailedSize- total unacked size bytes to refundfailedCount- total unacked fragments to refund overhead fortotalFail- true if the first (seq 0) outbound message failedshouldLogInfo- whether info logs are enabledshouldLogWarn- whether warn logs are enabled- Returns:
- true if the peer was dropped (the caller must return null)
hasOutbound
boolean hasOutbound()After a finishAndAllocate() pass, reports whether any outbound messages remain.- Returns:
- true if there are pending outbound messages
getVersion
public int getVersion()Peer SSU version.- Returns:
- the version number (1 for SSU1)
changePort
void changePort(int newPort) Change the remote port. Caller should sync; UDPTransport must remove and add to peersByRemoteHost map.- Parameters:
newPort- the new port number
getRemotePeer
Remote peer hash. The peer are we talking to. Non-null.- Returns:
- the remote peer hash
getKeyEstablishedTime
public long getKeyEstablishedTime()When the cipher and MAC keys were established. When were the current cipher and MAC keys established/rekeyed? This is the connection uptime.- Returns:
- the key establishment time
getClockSkew
public long getClockSkew()Clock skew. How far off is the remote peer from our clock, in milliseconds? A positive number means our clock is ahead of theirs.- Returns:
- the clock skew in ms
getLastSendTime
public long getLastSendTime()Last send time. When did we last send them a packet? Updated for data, relay, and peer test, but not acks, pings, or termination.- Returns:
- the last send time
getLastSendFullyTime
public long getLastSendFullyTime()Last send fully time.- Returns:
- the time in ms of the last send that did not need a retransmit
getLastReceiveTime
public long getLastReceiveTime()Last receive time. When did we last receive a packet from them? Updated for data, relay, and peer test, but not acks, pings, or termination.- Returns:
- the last receive time
getConsecutiveFailedSends
public int getConsecutiveFailedSends()Consecutive failed sends count.- Returns:
- how many sends to this peer have failed back to back, reset by the first send that succeeds
getSendWindowBytes
public int getSendWindowBytes()Send window bytes. How many bytes should we send to the peer in a second. 1st stat in CWND column, otherwise unused, candidate for removal.- Returns:
- the send window bytes
getSendWindowBytesRemaining
public int getSendWindowBytesRemaining()Send window bytes remaining.- Returns:
- the bytes still allowed in the current one-second send window
getRemoteIP
public byte[] getRemoteIP()Remote IP address bytes.- Returns:
- the raw address of the remote peer, 4 bytes for IPv4 and 16 for IPv6
getRemoteIPAddress
Cached remote IP address.- Returns:
- may be null if IP is invalid
getRemotePort
public int getRemotePort()Remote port.- Returns:
- the UDP port number the remote peer is reached on
getWeRelayToThemAs
public long getWeRelayToThemAs()Tag we relay to them as. If we are serving as an introducer to them, this is the the tag that they can publish that, when presented to us, will cause us to send a relay introduction to the current peer.- Returns:
- 0 (no relay) if unset previously
getTheyRelayToUsAs
public long getTheyRelayToUsAs()Tag they relay to us as. If they have offered to serve as an introducer to us, this is the tag we can use to publish that fact.- Returns:
- 0 (no relay) if unset previously
getMTU
public int getMTU()Maximum transmission unit.- Returns:
- the largest packet we will send to this peer, in bytes
getReceiveMTU
public int getReceiveMTU()Receive MTU estimate. Estimate how large the other side's MTU is. This could be wrong. It is used only for the HTML status.- Returns:
- the receive MTU
adjustClockSkew
void adjustClockSkew(long skew) Update the moving-average clock skew based on the current difference. The raw skew will be adjusted for RTT/2 here. A positive number means our clock is ahead of theirs.- Parameters:
skew- milliseconds, NOT adjusted for RTT.
setLastSendTime
void setLastSendTime(long when) Last send time. When did we last send them a packet? Updated for data, relay, and peer test, but not acks, pings, or termination.- Parameters:
when- the time to set
setLastReceiveTime
void setLastReceiveTime(long when) Last receive time. When did we last receive a packet from them? Updated for data, relay, and peer test, but not acks, pings, or termination.- Parameters:
when- the time to set
setLastPingTime
void setLastPingTime(long when) Last ping time. Note ping sent. Does not update last send time.- Parameters:
when- the time to set
getLastSendOrPingTime
long getLastSendOrPingTime()Latest of last sent, last ACK, last ping.- Returns:
- the latest time
getSendBps
public int getSendBps(long now) The Westwood+ bandwidth estimate.- Parameters:
now- the current time- Returns:
- the smoothed send transfer rate
getReceiveBps
public int getReceiveBps(long now) Receive Bps estimate. An approximation, for display only.- Parameters:
now- the current time- Returns:
- the smoothed receive transfer rate
incrementConsecutiveFailedSends
int incrementConsecutiveFailedSends()Increment consecutive failed sends.- Returns:
- the consecutive failed send count after this increment
getInactivityTime
public long getInactivityTime()Time since the peer was last heard from or sent to fully.- Returns:
- the time, in ms
allocateSendingBytes
Decrement the remaining bytes in the current period's window, returning true if the full size can be decremented, false if it cannot. If it is not decremented, the window size remaining is not adjusted at all.Caller should synch.
- Parameters:
state- the message to allocate send-window space fornow- current time in ms, recorded as the last send time when the allocation succeeds- Returns:
- true if the message's bytes were deducted from the send window, false if the concurrency limit or the remaining window blocked it
setWeRelayToThemAs
void setWeRelayToThemAs(long tag) If we are serving as an introducer to them, this is the the tag that they can publish that, when presented to us, will cause us to send a relay introduction to the current peer.- Parameters:
tag- 1 to Integer.MAX_VALUE, or 0 if relaying disabled
setTheyRelayToUsAs
void setTheyRelayToUsAs(long tag) If they have offered to serve as an introducer to us, this is the tag we can use to publish that fact.- Parameters:
tag- 1 to Integer.MAX_VALUE, or 0 if relaying disabled
getSlowStartThreshold
public int getSlowStartThreshold()Slow start threshold. Stat in SST column, otherwise unused - candidate for removal.- Returns:
- the slow start threshold
getConcurrentSends
public int getConcurrentSends()Concurrent sends count. 2nd stat in CWND column, otherwise unused - candidate for removal.- Returns:
- the concurrent sends count
getConcurrentSendWindow
public int getConcurrentSendWindow()Concurrent send window. 3rd stat in CWND column, otherwise unused, candidate for removal.- Returns:
- the concurrent send window
getConsecutiveSendRejections
public int getConsecutiveSendRejections()Consecutive send rejections count. 4th stat in CWND column, otherwise unused - candidate for removal.- Returns:
- the consecutive send rejections count
isInbound
public boolean isInbound()Whether this is an inbound connection.- Returns:
- true if we accepted this connection rather than dialling out
isIPv6
public boolean isIPv6()Whether the connection uses IPv6.- Returns:
- whether the peer is using IPv6
getIntroducerTime
long getIntroducerTime()Last introducer time.- Returns:
- the last time we used them as an introducer, or 0
setIntroducerTime
void setIntroducerTime()Record the last time we used them as an introducer.messageFullyReceived
We received the message specified completely.- Parameters:
messageId- the message IDbytes- if less than or equal to zero, message is a duplicate.
messagePartiallyReceived
void messagePartiallyReceived()We received a partial message, or we want to send some acks.messagePartiallyReceived
protected void messagePartiallyReceived(long now) We received a partial message, or we want to send some acks.- Parameters:
now- the current time
getInboundMessages
Map<Long, InboundMessageState> getInboundMessages()Fetch the internal id (Long) to InboundMessageState for incomplete inbound messages. Access to this map must be synchronized explicitly!- Returns:
- a map of message IDs to inbound message states
expireInboundMessages
int expireInboundMessages()Expire partially received inbound messages, returning how many are still pending. This should probably be fired periodically, in case a peer goes silent and we don't try to send them any messages (and don't receive any messages from them either).- Returns:
- the number of partially received inbound messages still pending
evictInboundMessage
Make room for one more partially-received inbound message. Expired and complete entries go first, since they are dead weight that simply has not been swept yet; only when none are left do we drop the live entry that has been waiting longest, which under a fragment flood is the one least likely ever to complete.The caller must hold
_inboundLock.- Parameters:
inbound- the per-peer map of partial inbound messages- Returns:
- the evicted state, already released, or null if the map was empty
congestionOccurred
private void congestionOccurred()Either they told us to back off, or we had to resend to get the data through. Caller should synch on this.nextCongestionRTO
static int nextCongestionRTO(int currentRTO, int rtt, int rttDeviation, int minRTO, int maxRTO) Compute the RTO to apply after a congestion signal.Congestion must not inflate RTO. RFC 6298 §5.5 doubling applies to retransmit-timer expiry, not every retransmit volley (which includes fast retransmit). Doubling here under sustained loss drove avgRTO to 33s while RTT stayed ~96ms — a death spiral that stalled each retransmit for half a minute and collapsed CWIN. With a known RTT, cap RTO at 4× the RFC 2988 estimate so historical inflation cannot outlive fresh latency samples; without an RTT sample, leave the current value unchanged (the RTT path in recalculateTimeouts() remains the sole authority for growth).
- Parameters:
currentRTO- current RTO in msrtt- smoothed RTT in ms, or <= 0 if unknownrttDeviation- RTT deviation in msminRTO- floor in msmaxRTO- ceiling in ms- Returns:
- the RTO to store, clamped to [minRTO, maxRTO]
congestionCooldownElapsed
static boolean congestionCooldownElapsed(long last, long now, int rto) Whether enough time has elapsed since the last congestion response to allow another one. Pure so the cooldown policy is unit-testable.The cooldown is
max(rto, CONGESTION_COOLDOWN_MIN_MS)so a low RTO cannot shrink the gap to ~1s and collapse the window every second under sustained loss.- Parameters:
last- congestion timestamp in ms, or 0 if nevernow- current time in msrto- current RTO in ms- Returns:
- true if a new congestion response may proceed
pathUnverifiedBlocksGrowth
static boolean pathUnverifiedBlocksGrowth(long now, long pathUnverifiedUntil) Whether send-window growth must be held because the path is unverified (SSU2 connection migration). Pure so the freeze gate is unit-testable.- Parameters:
now- current time in mspathUnverifiedUntil- freeze expiry in ms, or 0 if not frozen- Returns:
- true if window growth must not proceed
nextConcurrentLimit
static int nextConcurrentLimit(int numSends, int rtt, int current, int queued, int randomInt) Compute the next concurrent-messages limit after an ACK, pure so the AIMD tuning policy is unit-testable. Latency-based: additive increase while RTT is healthy (backlog-aware, ramping faster far from the cap), a soft *3/4 multiplicative decrease when RTT is well above target, a modest bump when the RTT hysteresis zone still has queued messages, and a hold otherwise. Retransmits (numSends >= 2) get a gentle /8 decrease to avoid grinding to the floor.- Parameters:
numSends- how many times the message was sent before the ACKrtt- the current smoothed RTT estimate (ms), or <= 0 if unknowncurrent- the current_concurrentMessagesAllowedqueued- how many messages are currently in_outboundQueuerandomInt- a uniform draw in [0,INIT_CONCURRENT_MSGS); only consumed whenrtt <= 0, pass 0 otherwise- Returns:
- the new concurrent-message limit
shouldGrowSendWindow
static boolean shouldGrowSendWindow(int sendWindow, int slowStartThreshold, int bytesACKed, float randomFloat) Whether an ACK should grow the send window. Classic slow-start / congestion-avoidance split (RFC 5681): grow unconditionally while at or below the slow-start threshold, otherwise grow probabilistically with probabilitybytesACKed / (2 * sendWindow). Pure so the growth gate is unit-testable.- Parameters:
sendWindow- the current_sendWindowBytesslowStartThreshold- the current_slowStartThresholdbytesACKed- the byte count newly ACKedrandomFloat- a uniform draw in [0, 1)- Returns:
- true if the window should grow by
bytesACKed
locked_messageACKed
private void locked_messageACKed(int bytesACKed, int maxPktSz, long lifetime, int numSends, boolean anyPending, boolean anyQueued) We sent a message which was ACKed containing the given # of bytes. Caller should synch on this.- Parameters:
bytesACKed- bytes newly confirmed by the ACK, added to the send windowmaxPktSz- full packet size of the ACKed message's first fragment, including the block header and IP/UDP overheadlifetime- ms from the first send to this ACK, the RTT samplenumSends- how many times the message was sent; below 2 the RTT, MTU and congestion-window updates runanyPending- true if other sent messages are still unACKed; false clears the retransmit timer and exits fast retransmitanyQueued- true if the outbound queue still holds messages, used to decide whether to nudge the message fragments job
messageACKed
private void messageACKed(int bytesACKed, int maxPktSz, long lifetime, int numSends, boolean anyPending, boolean anyQueued) We sent a message which was ACKed containing the given # of bytes. Takes the send-window lock and delegates tolocked_messageACKed(int, int, long, int, boolean, boolean).- Parameters:
bytesACKed- bytes newly confirmed by the ACKmaxPktSz- full packet size of the ACKed message's first fragmentlifetime- ms from the first send to this ACK, the RTT samplenumSends- how many times the message was sentanyPending- true if other sent messages are still unACKedanyQueued- true if the outbound queue still holds messages
recalculateTimeouts
private void recalculateTimeouts(long lifetime) Adjust the tcp-esque timeouts. Caller should synch on this.- Parameters:
lifetime- network RTT — time from first send to ACK (excludes queue time)
wantLargerMTU
static boolean wantLargerMTU(boolean success, int packetsTransmitted, int packetsRetransmitted) Whether a near-lossless transmission history warrants probing a larger MTU. Requires a successful send on a link with an observed retransmit ratio under 10%. Pure so the MTU tuning policy is unit-testable.- Parameters:
success- whether the triggering send completed without retransmitpacketsTransmitted- the value of_packetsTransmittedpacketsRetransmitted- the value of_packetsRetransmitted- Returns:
- true if the MTU should be considered for an increase
mtuIncreaseEligible
static boolean mtuIncreaseEligible(int mtu, int largeMTU, int maxPktSz, int mtuDecreases, int randomInt) Whether a larger MTU is eligible after a clean transmission. Requires the probe packet to have credibly hit the current MTU ceiling, and, after any prior decrease, a probabilistic gate (increasingly likely to allow the probe the longer the link has stayed healthy). Pure so the eligibility policy is unit-testable without the router RNG.- Parameters:
mtu- the value of_mtulargeMTU- the value of_largeMTUmaxPktSz- the size of the ACKed maximum-size packetmtuDecreases- the value of_mtuDecreasesrandomInt- the uniform draw in [0, mtuDecreases), consumed only whenmtuDecreases > 1; pass 0 otherwise- Returns:
- true if the MTU may be increased
mtuDecreaseEligible
static boolean mtuDecreaseEligible(int mtu, int minMTU, int maxPktSz) Whether the MTU should be reduced after a lossy transmission. Requires a packet that credibly hit the current ceiling. Pure so the eligibility policy is unit-testable.- Parameters:
mtu- the value of_mtuminMTU- the value of_minMTUmaxPktSz- the size of the retransmitted maximum-size packet- Returns:
- true if the MTU may be decreased
adjustMTU
private void adjustMTU(int maxPktSz, boolean success) Adjust upward if a large packet was successfully sent without retransmission. Adjust downward if a packet was retransmitted.Caller should synch on this.
- Parameters:
maxPktSz- the largest packet that was sentsuccess- was it sent successfully?
setHisMTU
void setHisMTU(int mtu) Remote peer's MTU.- Parameters:
mtu- the MTU to set
messageRetransmitted
void messageRetransmitted(int packets, int maxPktSz) Handle a message retransmission.- Parameters:
packets- the number of packets retransmittedmaxPktSz- the maximum packet size
packetsTransmitted
void packetsTransmitted(int packets) Record that packets were transmitted.- Parameters:
packets- the number of packets just handed to the transport, not bytes
reportLossRatio
private void reportLossRatio()Report the current retransmit ratio to the profile when it crosses a 5% bucket boundary since the last report. Bucketing keeps profile writes to at most one per bucket change per connection.No report until the connection has transmitted at least
ProfileOrganizer.PROP_LOSSY_MIN_PACKETSpackets, so the ratio is only ever based on a meaningful sample. The bucket is not advanced in that case, so the first bucket change after the minimum is reached still fires.Caller must hold _outboundLock.
getRTT
public int getRTT()Round trip time.- Returns:
- the RTT in ms
getRTO
public int getRTO()Retransmission timeout.Clamped to the current [MIN_RTO, MAX_RTO] so a peer that inflated before the Tuner cut the ceiling is not stuck on a stale high RTO.
- Returns:
- the RTO in ms
effectiveRTO
public static int effectiveRTO(int rto, int minRto, int maxRto) Clamp a raw RTO estimate into the active [minRto, maxRto] window.Extracted from
getRTO()so telemetry can report the value a packet actually waits under — raw estimates can sit outside the window (set at INIT_RTO, then re-clamped only on the next RTT sample) and would otherwise make the effective-vs-raw comparison untestable.- Parameters:
rto- the raw retransmission timeout estimateminRto- lower bound in msmaxRto- upper bound in ms; if below minRto it is ignored- Returns:
- the effective RTO in ms, within [minRto, maxRto]
getRTTDeviation
public int getRTTDeviation()RTT deviation.- Returns:
- the RTT deviation in ms
getMessagesSent
public int getMessagesSent()I2NP messages sent - does not include duplicates. As of 0.9.24, incremented when bandwidth is allocated just before sending, not when acked.- Returns:
- the messages sent count
getMessagesReceived
public int getMessagesReceived()I2NP messages received. As of 0.9.24, does not include duplicates.- Returns:
- the messages received count
getPacketsTransmitted
public int getPacketsTransmitted()Packets transmitted count.- Returns:
- how many packets have been handed to the transport for this peer
getPacketsRetransmitted
public int getPacketsRetransmitted()Packets retransmitted count.- Returns:
- how many packets had to be sent again after loss or congestion
getPacketsReceived
public int getPacketsReceived()Packets received count.- Returns:
- how many packets have arrived from this peer
getPacketsReceivedDuplicate
public int getPacketsReceivedDuplicate()Packets received duplicate count.- Returns:
- how many packets from this peer repeated data we had already stored
packetReceived
void packetReceived(int size) Record a received packet.- Parameters:
size- not including IP header, UDP header, MAC or IV
pathUnverified
void pathUnverified()Hold send-window growth while the path is unverified (SSU2 connection migration,limitSending). Freezes growth only for a short window; does not collapse CWIN or adjust RTO. Migration is a path change, not congestion, and a full collapse thrashes multi-homed peers. Growth resumes viapathVerified()or when the freeze expires.pathVerified
void pathVerified()Clear the path-unverified growth freeze (migration completed, failed, or cancelled — the current path is again the verified one).dataReceived
void dataReceived()Same as setLastReceivedTime(now).getLastACKSend
public long getLastACKSend()When we last sent an ACK.- Returns:
- the last ACK send time
clearWantedACKSendSince
void clearWantedACKSendSince()All acks have been sent - SSU 1 only, see override.getRemoteHostId
add
Add an outbound message state to the queue.- Parameters:
state- the outbound message state to add
dropOutbound
void dropOutbound()Drop all outbound messages.getOutboundMessageCount
public int getOutboundMessageCount()Outbound message count.- Returns:
- number of active outbound messages remaining (unsynchronized)
setMayDisconnect
public void setMayDisconnect()May disconnect to true.getMayDisconnect
public boolean getMayDisconnect()Whether we may disconnect.- Returns:
- true if we may disconnect
getNextDelay
int getNextDelay(long now) Uses cached oldest lifetime from the most recent finishAndAllocate() pass.- Parameters:
now- what time it is now- Returns:
- how long to wait before sending, or Integer.MAX_VALUE if we have nothing to send. If ready now, will return 0.
isBacklogged
public boolean isBacklogged()Whether the peer is dead or its outbound queue is backlogged.- Returns:
- true if the peer is dead or its outbound queue is full
fragmentSize
int fragmentSize()How much payload data can we shove in there?- Returns:
- MTU - 87, i.e. 533 or 1397 (IPv4), MTU - 107 (IPv6)
fragmentOverhead
int fragmentOverhead()Packet overhead plus room for acks.- Returns:
- 87 (IPv4), 107 (IPv6)
locked_shouldSend
Locks this.- Parameters:
state- the message to allocate send-window space fornow- current time in ms, used to throttle the rejection log- Returns:
- true if send-window space was allocated for the message, false if it was rejected and counted in udp.sendRejected
newlyAckedBytes
static int newlyAckedBytes(int unackedBefore, boolean complete, int unackedAfter) Compute the bytes newly confirmed by one incoming ACK for a single message: the full previously-unacked size when the message just became complete, otherwise only the delta newly covered by this ACK. Pure so the partial-ACK byte accounting is unit-testable.- Parameters:
unackedBefore- the message's unacked byte count before this ACKcomplete- whether this ACK completed the messageunackedAfter- the message's unacked byte count after this ACK- Returns:
- the byte count to credit toward the send window
acked
An ACK of a fragment was received.SSU 2 only.
- Parameters:
f- the SSU2 fragment whose acknowledgement has arrived- Returns:
- true if this fragment of the message was acked for the first time
fastRtxMode
Fast-retransmit progression as a function of the NACK count for a single message. ThresholdFAST_RTX_ACKS: the first exactly-threshold NACK starts fast retransmit (recovery begins, SST/cwnd set per RFC 5681 sec. 3.2 #2/#3); subsequent NACKs continue it (cwnd inflate per #4). Below threshold there is no action. Pure so the recovery cascade is unit-testable without router state.- Parameters:
nacks- the incremented NACK count for the message- Returns:
- NONE, START, or CONTINUE
highestSeqNumAcked
boolean highestSeqNumAcked(long highest) Enter or leave fast retransmit mode, and adjust SST and window variables accordingly. See RFC 5681 sec. 2.4.- Parameters:
highest- the highest sequence number that was acked- Returns:
- true if we have something to fast-retransmit
exitFastRetransmit
private void exitFastRetransmit()Leave fast retransmit mode if we were in it, and adjust SST and window variables accordingly. See RFC 5681 sec. 2.4.shouldRequestImmediateAck
protected boolean shouldRequestImmediateAck()SSU 2 only.- Returns:
- whether request immediate ack
loadFrom
Transfer the basic activity/state from the old peer to the current peerSSU 1 or 2.
- Parameters:
oldPeer- non-null
getTransport
UDPTransport getTransport()Convenience for OutboundMessageState so it can fail itself.- Returns:
- the UDPTransport this peer state belongs to
toShortString
String toShortString()Compact one-line peer identifier for log output: short hash, direction, version and remote host id. No stats, no newlines.- Returns:
- the short hash, direction, version and host id, on one line
toString