- All Implemented Interfaces:
SSU2Bitfield.Callback, SSU2Payload.PayloadCallback, SSU2Sender
Public only for UI peers page. Not a public API, not for external use.
SSU2 only.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate classA timer to send an ack-only packet.(package private) static enumDecision of the connection-migration classifier for MIGRATION_STATE_PENDING.private static enumState of one SSU2 connection migration.Nested classes/interfaces inherited from class PeerState
PeerState.FastRtxMode, PeerState.OutcomeModifier 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 SSU2BitfieldPS1 has _ackedMessages which is a map of message ID to sequence number.private final PeerState2.ACKTimerTimer scheduling acks and retransmits.private intReason code for destroying this state.private final AtomicIntegerHash of the last ack sent, to skip duplicates.private final ObjectLock for the connection migration state.private longWhen the next migration path challenge is due.private longWhen the current migration started.private PeerState2.MigrationStateCurrent connection migration state.private byte[]Our IP as the peer sees it.private intOur port as the peer sees it.private final AtomicLongNext SSU2 packet number to send.private byte[]Data of the path challenge we sent.private longPath challenges sent for the current migration.private RemoteHostIdNew host id pending confirmation during migration.private final CipherStateChaCha20 state for decrypting received packets.private final longConnection id we receive with.private final byte[]First header encryption key for receiving.private final byte[]Second header encryption key for receiving.private final SSU2BitfieldBitfield of received message numbers.private final CipherStateChaCha20 state for encrypting sent packets.private final longConnection id we send with.private final byte[]First header encryption key for sending.private final byte[]Second header encryption key for sending.private final ConcurrentHashMap<Long, List<PacketBuilder2.Fragment>> Sent messages awaiting acks, by message id.private static longConfigurable sent-messages sweep interval.private final ArrayDeque<Map.Entry<Long, List<PacketBuilder2.Fragment>>> Incremental expiry cursor over a snapshot of _sentMessages, so a tick examines a bounded number of entries instead of the whole map.private longWhen sent messages were last expired.private byte[][]Session Confirmed packets held for retransmission.private intSession Confirmed retransmit attempts so far.private longWhen a Session Confirmed was last sent.private static final intMessage numbers tracked in the received bitfield.static final intMTU advertised unless the profile overrides it.static final intDEFAULT_SSU_IPV4_MTU.static final intDEFAULT_SSU_IPV6_MTU.static final intLargest MTU we will advertise to SSU2 peers, in bytes.private static final longLast usable outbound packet number, see getNextPacketNumber().(package private) static final intPath challenge retransmissions before the migration is declared expired.(package private) static final longTotal time a path challenge may span, in ms, before it is declared expired.private static final intSession Confirmed retransmits before giving up.static final intMAX_SSU_IPV4_MTU.static final intMAX_SSU_IPV6_MTU.static final intMIN_MLKEM768_IPV4_MTU.static final intMIN_MLKEM768_IPV6_MTU.static final intSmallest MTU we will advertise to SSU2 peers, in bytes.static final intMIN_SSU_IPV4_MTU.static final intMIN_SSU_IPV6_MTU.(package private) static final longBase interval between path challenge sends in ms, doubled per retransmission.private static final intMax _sentMessages entries examined perexpireSentMessages(long)call.Fields inherited from class PeerState
_context, _dead, _inboundLock, _inboundMessages, _isInbound, _keyEstablishedTime, _lastACKSend, _log, _mtu, _packetsReceivedDuplicate, _remoteHostId, _remoteIP, _remoteIPAddress, _remotePeer, _remotePort, _rtt, _shortHash, _transport, _wantACKSendSince, CONGESTION_COOLDOWN_MIN_MS, LARGE_MTU, MAX_INBOUND_MESSAGES, MAX_IPV6_MTU, MAX_SEND_WINDOW_CEILING, MIN_IPV6_MTU, PATH_UNVERIFIED_FREEZE_MS, RETRANSMISSION_PERIOD_WIDTHModifier and TypeFieldDescriptionprotected final RouterContextThe router context.protected booleanHave we migrated away from this peer to another newer one?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.protected longWhen did we last send ACKs to the peer?protected final LogThe log.protected intWhat is the largest packet we can currently send to the peer?protected intHow many duplicate packets were received within the last RETRANSMISSION_PERIOD_WIDTH packets.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?protected intCurrent round trip time estimate.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).protected final UDPTransportThe UDP transport.protected longWhen did we decide we need to ACK to this peer?(package private) static final longFloor on the gap between full congestion responses (ms).static final intIPv4 maximum MTU.(package private) static final intHard cap on partially-received inbound messages held per peer.static final intIPv6 maximum MTU.(package private) static final intHeap-scaled CWIN ceiling: 1MB minimum, up to 16MB, roughly 1MB per 256MB of heap.static final intIPv6 minimum MTU.(package private) static final longHow long send-window growth stays frozen after a path-unverified migration signal (ms).(package private) static final longHow many packets will be considered within the retransmission rate calculation.Constructor Summary
ConstructorsConstructorDescriptionPeerState2(RouterContext ctx, UDPTransport transport, InetSocketAddress remoteAddress, Hash remotePeer, boolean isInbound, int rtt, CipherState sendCha, CipherState rcvCha, long sendID, long rcvID, byte[] sendHdrKey1, byte[] sendHdrKey2, byte[] rcvHdrKey2) A session with a remote peer over SSU2: the connection ids, the four cipher states and the header encryption keys are all fixed here, so the transport can build one without a separate handshake step.Method Summary
Modifier and TypeMethodDescriptionvoidbitSet(long pktNum) (package private) voidCaller should sync; UDPTransport must remove and add to peersByRemoteHost map.private booleancheckRetransmitSessionConfirmed(long now, boolean force) Only call for outbound, if we don't have ack 0 yet.private booleancheckRetransmitSessionConfirmed2(long now, boolean force) Only call for outbound, if we don't have ack 0 yet.(package private) voidAll acks have been sent.(package private) voidconfirmedPacketsSent(byte[][] data) Note that we just sent the SessionConfirmed packets and save them for retransmission.(package private) static PeerState2.MigrationPendingDecisiondecidePendingMigration(long now, boolean fromIsRemote, boolean fromIsPending, long migrationStarted, long sendCount, long nextSendTime) Classify what to do with a packet received while the connection is in MIGRATION_STATE_PENDING.(package private) voidOverridden to also clear sent-but-unacked fragments and cancel ACKTimer.private voidexpireSentMessages(long now) Expire complete or timed-out entries from _sentMessages, walking an incremental cursor instead of rescanning the whole map and every fragment list on every tick.(package private) List<OutboundMessageState> finishAndAllocate(long now) Single-pass combined cleanup + send allocation, overriding the base class to incorporate SSU2-specific _sentMessages cleanup and SessionConfirmed retransmit logic.(package private) intPacket overhead This is 5 bytes too high for first or only fragment, because the 9 byte I2NP header is included in that fragment.(package private) intHow much payload data can we shove in there? This is 5 bytes too low for first or only fragment, because the 9 byte I2NP header is included in that fragment.voidfragmentsSent(long pktNum, int length, List<PacketBuilder2.Fragment> fragments) Record the mapping of packet number to what fragments were in it, so we can process acks.Bitfield of messages acknowledged to the peer.(package private) intThe destroy reason, for PeerStateDestroyed only, after we are dead.bytegetFlags()Flag byte to be sent in header.longNext outbound packet number, starts at 1 for Alice (0 is Session Confirmed) and 0 for Bob.protected longFor PeerStateDestroyed only, after we are dead.(package private) byte[]getOurIP()As received in the Address Block in the handshake, or subsequently in the data phase.(package private) intAs received in the Address Block in the handshake, or subsequently in the data phase.(package private) CipherStateThe inbound cipher state, paired with the peer's first header key.(package private) longThe connection ID we expect to receive packets with.(package private) byte[]The first header encryption key for received packets.(package private) byte[]The second header encryption key for received packets.Bitfield of messages received from the peer.private UDPPacket[]The saved SessionConfirmed packets for retransmission.Caller must sync on returned object when encrypting.longThe send connection ID.byte[]The send header encryption key 1.byte[]The send header encryption key 2.static longCurrent sent-messages cleanup interval.intThe version.voidgotACK(long ackThru, int acks, byte[] ranges) Process a received ACK block.voidgotAddress(byte[] ip, int port) Process a received Address block, updating our external address.voidgotDateTime(long time) Process a received DateTime block.voidgotFragment(byte[] data, int off, int len, long messageId, int frag, boolean isLast) Process a received Fragment block.voidgotI2NP(I2NPMessage msg) Process a received I2NP block.voidgotOptions(byte[] options, boolean isHandshake) Process a received Options block.voidgotPathChallenge(RemoteHostId from, byte[] data) Process a received PathChallenge block, replying with a PathResponse.voidgotPathResponse(RemoteHostId from, byte[] data) Process a received PathResponse block.voidgotPeerTest(int msg, int status, Hash h, byte[] data) Process a received PeerTest block.voidgotRelayIntro(Hash aliceHash, byte[] data) Process a received RelayIntro block.voidgotRelayRequest(byte[] data) Process a received RelayRequest block.voidgotRelayResponse(int status, byte[] data) Process a received RelayResponse block.voidgotRelayTag(long tag) Process a received RelayTag block.voidProcess a received RelayTagRequest block, offering a relay tag if possible.voidgotRI(RouterInfo ri, boolean isHandshake, boolean flood) Process a received RouterInfo block, storing and possibly flooding it.voidgotRIFragment(byte[] data, boolean isHandshake, boolean flood, boolean isGzipped, int frag, int totalFrags) Process a received RouterInfo fragment block.voidgotTermination(int reason, long count) Process a received Termination block.voidgotToken(long token, long expires) Process a received Token block.private booleanhandleMigrationNone(RemoteHostId from, long n, UDPPacket packet) Connection migration attempt while in MIGRATION_STATE_NONE.private booleanhandleMigrationPending(RemoteHostId from, UDPPacket packet) Connection migration attempt while in MIGRATION_STATE_PENDING.(package private) booleanisDead()Whether a SessionDestroy has been sent or received on this session, so the transport can drop the session without a second teardown exchange.protected voidmessagePartiallyReceived(long now) Overridden to use our version of ACKTimer.private voidDo what MessageReceiver does, but inline and for SSU2.(package private) voidreceivePacket(RemoteHostId from, UDPPacket packet) From different than expected source IP/port.(package private) voidreceivePacket(UDPPacket packet) Receives and decrypts the given packet.(package private) voidsendAck0()Send immediate ACK 0 of Session Confirmed.private voidsendPathChallenge(InetAddress toIP, int toPort) Caller must synch on _migrationState.intNumber of pending sent-but-unacked packet entries.voidsetDestroyReason(int reason) Record why the peer was destroyed, for the Destroy message.(package private) voidsetOurAddress(byte[] ip, int port) For initialization by IES2/OES2 only.static voidsetSentMessagesCleanTime(long ms) Sent-messages cleanup interval, called by Tuner.(package private) static booleanshouldInitiateMigration(boolean ipFamilyMatch, boolean isHighestSet, boolean validPort, boolean validIP) Decide whether a packet from a new source address may initiate a connection migration while the connection is in MIGRATION_STATE_NONE.private booleanWhether debug logging is on for this peer.Methods inherited from class PeerState
acked, add, adjustClockSkew, cappedRefund, changePort, classifyOutcome, congestionCooldownElapsed, dataReceived, effectiveRTO, evictInboundMessage, expireInboundMessages, fastRtxMode, getAckFrequency, getAggregateStats, getClockSkew, getClockSkewFudge, getConcurrentSends, getConcurrentSendWindow, getConsecutiveFailedSends, getConsecutiveSendRejections, getInactivityTime, getInboundMessages, getInitConcurrentMsgs, getInitRTO, getIntroducerTime, getKeyEstablishedTime, getLastACKSend, getLastReceiveTime, getLastSendFullyTime, getLastSendOrPingTime, getLastSendTime, getMaxConcurrentMessages, getMaxRTO, getMaxSendWindow, getMaxSendWindowCeiling, getMayDisconnect, getMessagesReceived, getMessagesSent, getMinConcurrentMsgs, getMinRTO, getMTU, getNextDelay, getOutboundMessageCount, getOutboundMsgExpiration, getOutboundQueueSize, getPacketsReceived, getPacketsReceivedDuplicate, getPacketsRetransmitted, getPacketsTransmitted, getPostRTOWindowMTUs, getReceiveBps, getReceiveMTU, getRemoteHostId, getRemoteIP, getRemoteIPAddress, getRemotePeer, getRemotePort, getRTO, getRTT, getRTTDeviation, getSendBps, getSendWindowBytes, getSendWindowBytesRemaining, getSlowStartThreshold, getTheyRelayToUsAs, getTransport, getWeRelayToThemAs, hasOutbound, highestSeqNumAcked, incrementConsecutiveFailedSends, isBacklogged, isInbound, isIPv6, isTotalFail, loadConfig, loadFrom, messageFullyReceived, messagePartiallyReceived, messageRetransmitted, mtuDecreaseEligible, mtuIncreaseEligible, newlyAckedBytes, nextConcurrentLimit, nextCongestionRTO, packetReceived, packetsTransmitted, pathUnverified, pathUnverifiedBlocksGrowth, pathVerified, reachedRetransmitCap, retransmitFireTime, setAckFrequency, setHisMTU, setInitConcurrentMsgs, setInitRTO, setIntroducerTime, setLastPingTime, setLastReceiveTime, setLastSendTime, setMaxConcurrentMessages, setMaxRTO, setMaxSendWindow, setMayDisconnect, setMinConcurrentMsgs, setMinRTO, setOutboundMsgExpiration, setOutboundQueueSize, setPostRTOWindowMTUs, setTheyRelayToUsAs, setWeRelayToThemAs, shouldGrowSendWindow, shouldRequestImmediateAck, shouldSkipFastRetransmit, toShortString, toString, wantLargerMTUModifier 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.(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) static booleancongestionCooldownElapsed(long last, long now, int rto) Whether enough time has elapsed since the last congestion response to allow another one.(package private) voidSame as setLastReceivedTime(now).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.(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.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 inPeerState.setMaxSendWindow(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.intSlow start threshold.longTag they relay to us as.(package private) UDPTransportConvenience for OutboundMessageState so it can fail itself.longTag we relay to them as.(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 peer(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.(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.(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).(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.Methods inherited from class Object
clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface SSU2Sender
getMTU, getRemoteHostId, getRemoteIPAddress, getRemotePort, isIPv6
Field Details
_sendConnID
private final long _sendConnIDConnection id we send with._rcvConnID
private final long _rcvConnIDConnection id we receive with._packetNumber
Next SSU2 packet number to send.MAX_PACKET_NUMBER
private static final long MAX_PACKET_NUMBERLast usable outbound packet number, see getNextPacketNumber(). @since 0.9.71+- See Also:
_lastAckHashCode
Hash of the last ack sent, to skip duplicates._sendCha
ChaCha20 state for encrypting sent packets._rcvCha
ChaCha20 state for decrypting received packets._sendHeaderEncryptKey1
private final byte[] _sendHeaderEncryptKey1First header encryption key for sending._rcvHeaderEncryptKey1
private final byte[] _rcvHeaderEncryptKey1First header encryption key for receiving._sendHeaderEncryptKey2
private final byte[] _sendHeaderEncryptKey2Second header encryption key for sending._rcvHeaderEncryptKey2
private final byte[] _rcvHeaderEncryptKey2Second header encryption key for receiving._receivedMessages
Bitfield of received message numbers._ackedMessages
PS1 has _ackedMessages which is a map of message ID to sequence number. Here we have the reverse, a bitfield of acked packet (sequence) numbers, and map of unacked packet (sequence) numbers to the fragments that packet contained._sentMessages
Sent messages awaiting acks, by message id._ackTimer
Timer scheduling acks and retransmits._sentMessagesLastExpired
private long _sentMessagesLastExpiredWhen sent messages were last expired._sentMessagesExpiryCursor
Incremental expiry cursor over a snapshot of _sentMessages, so a tick examines a bounded number of entries instead of the whole map. Only touched from the PacketPusher thread via finishAndAllocate()._ourIP
private volatile byte[] _ourIPOur IP as the peer sees it._ourPort
private volatile int _ourPortOur port as the peer sees it._destroyReason
private volatile int _destroyReasonReason code for destroying this state._sessConfForReTX
private byte[][] _sessConfForReTXSession Confirmed packets held for retransmission._sessConfSentTime
private long _sessConfSentTimeWhen a Session Confirmed was last sent._sessConfSentCount
private int _sessConfSentCountSession Confirmed retransmit attempts so far._migrationLock
Lock for the connection migration state._migrationState
Current connection migration state._migrationStarted
private long _migrationStartedWhen the current migration started._migrationNextSendTime
private long _migrationNextSendTimeWhen the next migration path challenge is due._pathChallengeData
private byte[] _pathChallengeDataData of the path challenge we sent._pathChallengeSendCount
private long _pathChallengeSendCountPath challenges sent for the current migration._pendingRemoteHostId
New host id pending confirmation during migration.MAX_PATH_CHALLENGE_SENDS
static final int MAX_PATH_CHALLENGE_SENDSPath challenge retransmissions before the migration is declared expired.- See Also:
MAX_PATH_CHALLENGE_TIME
static final long MAX_PATH_CHALLENGE_TIMETotal time a path challenge may span, in ms, before it is declared expired.- See Also:
PATH_CHALLENGE_DELAY
static final long PATH_CHALLENGE_DELAYBase interval between path challenge sends in ms, doubled per retransmission.- See Also:
MIN_SSU_IPV4_MTU
MAX_SSU_IPV4_MTU
DEFAULT_SSU_IPV4_MTU
MIN_SSU_IPV6_MTU
MAX_SSU_IPV6_MTU
DEFAULT_SSU_IPV6_MTU
MIN_MTU
public static final int MIN_MTUSmallest MTU we will advertise to SSU2 peers, in bytes.- See Also:
MAX_MTU
public static final int MAX_MTULargest MTU we will advertise to SSU2 peers, in bytes.- See Also:
DEFAULT_MTU
public static final int DEFAULT_MTUMTU advertised unless the profile overrides it.- See Also:
MIN_MLKEM768_IPV4_MTU
MIN_MLKEM768_IPV6_MTU
BITFIELD_SIZE
private static final int BITFIELD_SIZEMessage numbers tracked in the received bitfield.- See Also:
MAX_SESS_CONF_RETX
private static final int MAX_SESS_CONF_RETXSession Confirmed retransmits before giving up.- See Also:
_sentMessagesCleanTime
private static volatile long _sentMessagesCleanTimeConfigurable sent-messages sweep interval. Default 60s, shortened under load.SENT_MESSAGES_EXPIRE_BATCH
private static final int SENT_MESSAGES_EXPIRE_BATCHMax _sentMessages entries examined perexpireSentMessages(long)call. @since 0.9.71+.- See Also:
Constructor Details
PeerState2
public PeerState2(RouterContext ctx, UDPTransport transport, InetSocketAddress remoteAddress, Hash remotePeer, boolean isInbound, int rtt, CipherState sendCha, CipherState rcvCha, long sendID, long rcvID, byte[] sendHdrKey1, byte[] sendHdrKey2, byte[] rcvHdrKey2) A session with a remote peer over SSU2: the connection ids, the four cipher states and the header encryption keys are all fixed here, so the transport can build one without a separate handshake step.If inbound, caller MUST immediately call setWeRelayToThemAs() (if nonzero) and sendAck0().
- Parameters:
ctx- the router contexttransport- the UDP transport this session runs onremoteAddress- the peer's address, which may change on migrationremotePeer- the peer's router hashisInbound- true if the peer opened the session, false if we didrtt- from the EstablishState, or 0 if not availablesendCha- the outbound cipher state for payload blocksrcvCha- the inbound cipher state for payload blockssendID- the connection id we send in every block headerrcvID- the connection id the peer sends in every block headersendHdrKey1- the first outbound header encryption keysendHdrKey2- the second outbound header encryption keyrcvHdrKey2- the second inbound header encryption key
Method Details
shouldLogDebug
private boolean shouldLogDebug()Whether debug logging is on for this peer.- Returns:
- true if debug logging is enabled
getSentMessagesCleanTime
public static long getSentMessagesCleanTime()Current sent-messages cleanup interval.- Returns:
- current sent-messages cleanup interval in ms
setSentMessagesCleanTime
public static void setSentMessagesCleanTime(long ms) Sent-messages cleanup interval, called by Tuner.- Parameters:
ms- cleanup interval in ms, clamped to [2000, 300000]
sendAck0
void sendAck0()Send immediate ACK 0 of Session Confirmed. Inbound only. Bundle relay tag if requested, seeInboundEstablishState2.getVersion
public int getVersion()The version.- Overrides:
getVersionin classPeerState- Returns:
- 2, as this class implements SSU2
fragmentSize
int fragmentSize()How much payload data can we shove in there? This is 5 bytes too low for first or only fragment, because the 9 byte I2NP header is included in that fragment. Does NOT leave any room for acks with a full-size fragment.- Overrides:
fragmentSizein classPeerState- Returns:
- MTU - 68 (IPv4), MTU - 88 (IPv6)
fragmentOverhead
int fragmentOverhead()Packet overhead This is 5 bytes too high for first or only fragment, because the 9 byte I2NP header is included in that fragment. Does NOT leave any room for acks with a full-size fragment.- Overrides:
fragmentOverheadin classPeerState- Returns:
- 68 (IPv4), 88 (IPv6)
clearWantedACKSendSince
void clearWantedACKSendSince()All acks have been sent.- Overrides:
clearWantedACKSendSincein classPeerState
messagePartiallyReceived
protected void messagePartiallyReceived(long now) Overridden to use our version of ACKTimer.- Overrides:
messagePartiallyReceivedin classPeerState- Parameters:
now- the current time
expireSentMessages
private void expireSentMessages(long now) Expire complete or timed-out entries from _sentMessages, walking an incremental cursor instead of rescanning the whole map and every fragment list on every tick.The cursor holds a snapshot of the map taken when it runs dry; entries acked in the meantime are skipped by the identity check, and newly added entries are picked up on the next refill. An entry is removed only when every fragment's message is complete or expired, so it never expires early. One pass covers the whole cursor, so retention matches the old full scan's single tick.
Only called from
finishAndAllocate(long)on the PacketPusher thread, so the cursor needs no synchronization. Failure detection is unaffected: that is the "ahead > BITFIELD_SIZE" check infinishAndAllocate(long), which runs on its own schedule.- Parameters:
now- current time, for the expiry test
finishAndAllocate
Single-pass combined cleanup + send allocation, overriding the base class to incorporate SSU2-specific _sentMessages cleanup and SessionConfirmed retransmit logic.- Overrides:
finishAndAllocatein classPeerState- Parameters:
now- current time in ms, used as the expiry base for the messages that are allocated here- Returns:
- messages to send, or null if none ready
checkRetransmitSessionConfirmed
private boolean checkRetransmitSessionConfirmed(long now, boolean force) Only call for outbound, if we don't have ack 0 yet.- Parameters:
now- the current time in ms for the retransmit timerforce- ignore timer, always send- Returns:
- success, false if total fail
checkRetransmitSessionConfirmed2
private boolean checkRetransmitSessionConfirmed2(long now, boolean force) Only call for outbound, if we don't have ack 0 yet.- Parameters:
now- the current time in ms for the retransmit timerforce- ignore timer, always send- Returns:
- success, false if total fail
getNextPacketNumber
Next outbound packet number, starts at 1 for Alice (0 is Session Confirmed) and 0 for Bob. The packet number is a 4-byte header field and doubles as the ChaCha20 and Poly1305 nonce, so the session must not outlive the number space - wrapping would silently reuse keystream and the Poly1305 key. A busy router can burn 2^32 numbers in hours, hence the guard. Leaves 256 numbers of headroom for the destroy packets sent after death.- Specified by:
getNextPacketNumberin interfaceSSU2Sender- Returns:
- the next packet number
- Throws:
IOException- if the number space is exhausted, killing the session so the caller re-handshakes with fresh keys
getNextPacketNumberNoThrow
protected long getNextPacketNumberNoThrow()For PeerStateDestroyed only, after we are dead.- Returns:
- the next packet number no throw
getSendConnID
public long getSendConnID()The send connection ID. For PeerStateDestroyed only, after we are dead.- Specified by:
getSendConnIDin interfaceSSU2Sender- Returns:
- the send conn i d
getSendCipher
Caller must sync on returned object when encrypting.- Specified by:
getSendCipherin interfaceSSU2Sender- Returns:
- the send cipher
getSendHeaderEncryptKey1
public byte[] getSendHeaderEncryptKey1()The send header encryption key 1. Caller must sync on returned object when encrypting.- Specified by:
getSendHeaderEncryptKey1in interfaceSSU2Sender- Returns:
- the send header encrypt key1
getSendHeaderEncryptKey2
public byte[] getSendHeaderEncryptKey2()The send header encryption key 2. Caller must sync on returned object when encrypting.- Specified by:
getSendHeaderEncryptKey2in interfaceSSU2Sender- Returns:
- the send header encrypt key2
setDestroyReason
public void setDestroyReason(int reason) Record why the peer was destroyed, for the Destroy message.- Specified by:
setDestroyReasonin interfaceSSU2Sender- Parameters:
reason- theSSU2Utiltermination code, echoed to the peer in a SessionDestroy and ignored once destroyed
getRcvConnID
long getRcvConnID()The connection ID we expect to receive packets with.- Returns:
- the receive connection ID
getRcvHeaderEncryptKey1
byte[] getRcvHeaderEncryptKey1()The first header encryption key for received packets.- Returns:
- the receive header key 1
getRcvHeaderEncryptKey2
byte[] getRcvHeaderEncryptKey2()The second header encryption key for received packets.- Returns:
- the receive header key 2
getDestroyReason
int getDestroyReason()The destroy reason, for PeerStateDestroyed only, after we are dead.- Returns:
- 0 (REASON_UNSPEC) if unset
getRcvCipher
CipherState getRcvCipher()The inbound cipher state, paired with the peer's first header key.- Returns:
- the inbound payload cipher state
setOurAddress
void setOurAddress(byte[] ip, int port) For initialization by IES2/OES2 only.- Parameters:
ip- our address as the peer will see it, 4 or 16 bytesport- our port as the peer will see it
getOurIP
byte[] getOurIP()As received in the Address Block in the handshake, or subsequently in the data phase. Unvalidated. Also, if a transient IPv6 address, may be deprecated and not match our current non-deprecated IPv6 address.- Returns:
- our address as the peer sees it, 4 or 16 bytes, or null if unset
getOurPort
int getOurPort()As received in the Address Block in the handshake, or subsequently in the data phase. Unvalidated.- Returns:
- our port as the peer sees it, or 0 if unset
getReceivedMessages
Bitfield of messages received from the peer.- Specified by:
getReceivedMessagesin interfaceSSU2Sender- Returns:
- the received messages
getAckedMessages
Bitfield of messages acknowledged to the peer.- Specified by:
getAckedMessagesin interfaceSSU2Sender- Returns:
- the acked messages
receivePacket
Receives and decrypts the given packet.- Parameters:
packet- fully encrypted, header and body decryption will be done here
receivePacket
From different than expected source IP/port.- Parameters:
from- source address the packet did not come from; a mismatch causes the packet to be droppedpacket- fully encrypted, header and body decryption will be done here
handleMigrationNone
Connection migration attempt while in MIGRATION_STATE_NONE.A packet from a host different from the current remote host starts a migration only when it passes the pure
shouldInitiateMigration(boolean, boolean, boolean, boolean)classifier (IP family match, highest-set ordering rule, validated source). Path Response processing happens earlier in receivePacket, so a completed migration has already reset the state before this runs. Sending is limited only while a challenge is actually outstanding; a refused migration must not freeze the verified path.Must be called with
_migrationLockheld.- Parameters:
from- source address of the received packet, or nulln- packet (sequence) number of the received packetpacket- the received packet (source address used for the challenge)- Returns:
- true if sending must be limited while the connection is migrating
handleMigrationPending
Connection migration attempt while in MIGRATION_STATE_PENDING.The packet source is classified by the pure
decidePendingMigration(long, boolean, boolean, long, long, long)method. This method applies the side effects (cancel/timeout state reset, path-challenge retransmission with exponential backoff).Must be called with
_migrationLockheld.- Parameters:
from- source address of the received packet, or nullpacket- the received packet (source address used for retransmission)- Returns:
- true if sending must be limited while the connection is migrating
shouldInitiateMigration
static boolean shouldInitiateMigration(boolean ipFamilyMatch, boolean isHighestSet, boolean validPort, boolean validIP) Decide whether a packet from a new source address may initiate a connection migration while the connection is in MIGRATION_STATE_NONE.The source IP family must match the current remote host, the packet must be the highest sequence received so far (QUIC ordering rule, protects against reordered packets driving a migration to an attacker-chosen address), and the source must pass both port and address validation.
- Parameters:
ipFamilyMatch- true if the source IP family matches the current remote hostisHighestSet- true if the packet is the highest sequence received so farvalidPort- true if the source port is validvalidIP- true if the source IP passes transport address validation- Returns:
- a boolean indicating whether to start the migration challenge
decidePendingMigration
static PeerState2.MigrationPendingDecision decidePendingMigration(long now, boolean fromIsRemote, boolean fromIsPending, long migrationStarted, long sendCount, long nextSendTime) Classify what to do with a packet received while the connection is in MIGRATION_STATE_PENDING. Pure decision; side effects are applied by the caller. Order of precedence: the current remote host wins (cancel), the timeout/send-budget check wins over retransmission.- Parameters:
now- current time msfromIsRemote- true if the source is the current (pre-migration) remote hostfromIsPending- true if the source is the pending migration targetmigrationStarted- ms at which the migration was startedsendCount- number of path challenges already sentnextSendTime- ms at which the next retransmission is due- Returns:
- the pending-migration action to take
sendPathChallenge
Caller must synch on _migrationState.- Parameters:
toIP- the address to send the path challenge totoPort- the port to send the path challenge to
gotDateTime
public void gotDateTime(long time) Process a received DateTime block.- Specified by:
gotDateTimein interfaceSSU2Payload.PayloadCallback- Parameters:
time- time in milliseconds since epoch
gotOptions
public void gotOptions(byte[] options, boolean isHandshake) Process a received Options block.- Specified by:
gotOptionsin interfaceSSU2Payload.PayloadCallback- Parameters:
options- the option dataisHandshake- true only for message 3 part 2
gotRI
Process a received RouterInfo block, storing and possibly flooding it.- Specified by:
gotRIin interfaceSSU2Payload.PayloadCallback- Parameters:
ri- will already be validatedisHandshake- true only for message 3 part 2flood- true if this is a floodfill router- Throws:
DataFormatException- if the RouterInfo block is malformed
gotRIFragment
public void gotRIFragment(byte[] data, boolean isHandshake, boolean flood, boolean isGzipped, int frag, int totalFrags) Process a received RouterInfo fragment block.- Specified by:
gotRIFragmentin interfaceSSU2Payload.PayloadCallback- Parameters:
data- is first gzipped and then fragmentedisHandshake- true only for message 3 part 2flood- true if this is a floodfill routerisGzipped- true if the data is gzippedfrag- fragment number (0-based)totalFrags- total number of fragments
gotAddress
public void gotAddress(byte[] ip, int port) Process a received Address block, updating our external address.- Specified by:
gotAddressin interfaceSSU2Payload.PayloadCallback- Parameters:
ip- IP address bytesport- the port number to send
gotRelayTagRequest
public void gotRelayTagRequest()Process a received RelayTagRequest block, offering a relay tag if possible.- Specified by:
gotRelayTagRequestin interfaceSSU2Payload.PayloadCallback
gotRelayTag
public void gotRelayTag(long tag) Process a received RelayTag block.- Specified by:
gotRelayTagin interfaceSSU2Payload.PayloadCallback- Parameters:
tag- the relay tag
gotRelayRequest
public void gotRelayRequest(byte[] data) Process a received RelayRequest block.- Specified by:
gotRelayRequestin interfaceSSU2Payload.PayloadCallback- Parameters:
data- excludes flag, includes signature
gotRelayResponse
public void gotRelayResponse(int status, byte[] data) Process a received RelayResponse block.- Specified by:
gotRelayResponsein interfaceSSU2Payload.PayloadCallback- Parameters:
status- 0 = accept, 1-255 = rejectdata- excludes flag, includes signature
gotRelayIntro
Process a received RelayIntro block.- Specified by:
gotRelayIntroin interfaceSSU2Payload.PayloadCallback- Parameters:
aliceHash- hash of the introducerdata- excludes flag, includes signature
gotPeerTest
Process a received PeerTest block.- Specified by:
gotPeerTestin interfaceSSU2Payload.PayloadCallback- Parameters:
msg- 1-7status- 0 = accept, 1-255 = rejecth- Alice or Charlie hash for msg 2 and 4, null for msg 1, 3, 5-7data- excludes flag, includes signature
gotToken
public void gotToken(long token, long expires) Process a received Token block.- Specified by:
gotTokenin interfaceSSU2Payload.PayloadCallback- Parameters:
token- the session token to attach to the next peer testexpires- token expiration time in milliseconds
gotI2NP
Process a received I2NP block.- Specified by:
gotI2NPin interfaceSSU2Payload.PayloadCallback- Parameters:
msg- the parsed I2NP message
gotFragment
public void gotFragment(byte[] data, int off, int len, long messageId, int frag, boolean isLast) throws DataFormatException Process a received Fragment block.- Specified by:
gotFragmentin interfaceSSU2Payload.PayloadCallback- Parameters:
data- buffer containing fragment dataoff- offset in datalen- length of data to copymessageId- unique message identifierfrag- fragment number (0-based)isLast- whether this is the last fragment- Throws:
DataFormatException- if the fragment is malformed
gotACK
public void gotACK(long ackThru, int acks, byte[] ranges) Process a received ACK block.- Specified by:
gotACKin interfaceSSU2Payload.PayloadCallback- Parameters:
ackThru- highest contiguous sequence number acknowledgedacks- number of additional acknowledgments beyond ackThruranges- null if none
gotTermination
public void gotTermination(int reason, long count) Process a received Termination block.- Specified by:
gotTerminationin interfaceSSU2Payload.PayloadCallback- Parameters:
reason- termination reason codecount- in theory could wrap around to negative, but very unlikely
gotPathChallenge
Process a received PathChallenge block, replying with a PathResponse.- Specified by:
gotPathChallengein interfaceSSU2Payload.PayloadCallback- Parameters:
from- null if unknowndata- the challenge bytes, which must be copied out
gotPathResponse
Process a received PathResponse block.- Specified by:
gotPathResponsein interfaceSSU2Payload.PayloadCallback- Parameters:
from- null if unknowndata- the response bytes, which must be copied out
changeAddress
Caller should sync; UDPTransport must remove and add to peersByRemoteHost map.- Parameters:
id- the new remote host id, carrying both the address and the port
receiveMessage
Do what MessageReceiver does, but inline and for SSU2. Will always be more than one fragment.- Parameters:
state- the complete multi-fragment message to reassemble and queue
fragmentsSent
Record the mapping of packet number to what fragments were in it, so we can process acks.- Specified by:
fragmentsSentin interfaceSSU2Sender- Parameters:
pktNum- the packet number the fragments were sent underlength- including ip/udp header, for logging onlyfragments- fragment list
bitSet
public void bitSet(long pktNum) Callback fromSSU2Bitfield.forEachAndNot(SSU2Bitfield, SSU2Bitfield.Callback). A new ack was received.- Specified by:
bitSetin interfaceSSU2Bitfield.Callback- Parameters:
pktNum- the absolute message number that was newly set
confirmedPacketsSent
void confirmedPacketsSent(byte[][] data) Note that we just sent the SessionConfirmed packets and save them for retransmission. This is only called the first time. For retransmit see allocateSend() above.- Parameters:
data- the SessionConfirmed packet bodies, retained only if this is the first send so a retransmission can resend the same bytes
getRetransmitSessionConfirmedPackets
The saved SessionConfirmed packets for retransmission.- Returns:
- null if not sent or already got the ack
getFlags
public byte getFlags()Flag byte to be sent in header.- Specified by:
getFlagsin interfaceSSU2Sender- Returns:
- the header flag byte,
0x01when the send window has under a third of its capacity left and an immediate ack is requested, otherwise0
isDead
boolean isDead()Whether a SessionDestroy has been sent or received on this session, so the transport can drop the session without a second teardown exchange.- Returns:
- true once the session has been destroyed
sentMessagesSize
public int sentMessagesSize()Number of pending sent-but-unacked packet entries.- Returns:
- the number of packet entries awaiting an ACK, not a byte count
dropOutbound
void dropOutbound()Overridden to also clear sent-but-unacked fragments and cancel ACKTimer. Prevents lingering references from keeping orphaned PeerState2 alive.- Overrides:
dropOutboundin classPeerState