mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
84 lines
3.9 KiB
Go
84 lines
3.9 KiB
Go
package tcp
|
|
|
|
// LossRecovery abstracts TCP packet-loss recovery: RTO, congestion control and
|
|
// any similar algorithm that observes segment traffic and steers the
|
|
// connection's transmit behaviour. As far as the tcp package is concerned these
|
|
// are all the same thing — packet-loss recovery algorithms — so they share one
|
|
// interface (see discussion #157).
|
|
//
|
|
// The tcp package stays free of any time source: the current monotonic time in
|
|
// nanoseconds (the func() int64 convention used across lneto) is passed in at
|
|
// each hook boundary. It originates from [ConnConfig.Nanotime] and satisfies the
|
|
// "WHEN was this segment rx/tx'd" requirement without a clock living inside the
|
|
// state machine, which also keeps implementations deterministic for testing
|
|
// (see issue #140).
|
|
//
|
|
// The interface is intentionally free of errors: an implementation handles or
|
|
// reports its own errors rather than propagating them into lneto internals.
|
|
//
|
|
// Introspection (smoothed RTT, current window, ...) is deliberately left off the
|
|
// interface; expose it on the concrete implementation the caller constructs and
|
|
// hands to [ConnConfig].
|
|
type LossRecovery interface {
|
|
// Reset returns the implementation to its initial, pre-connection state. It
|
|
// is invoked whenever the connection is (re)opened or aborted so a single
|
|
// LossRecovery value can be reused across the lifetime of connection reuse
|
|
// (see discussion #115).
|
|
Reset()
|
|
|
|
// NextDeadline returns the monotonic-nanosecond instant at which the
|
|
// connection must next be serviced by a transmit attempt — typically the RTO
|
|
// expiry. A return of 0 means there is no pending deadline. It replaces a
|
|
// poll/atomic-flag scheme with a deadline the caller's event loop can
|
|
// schedule against.
|
|
NextDeadline() int64
|
|
|
|
// PreRx is called for every segment received on the TCP port before the
|
|
// state machine processes it, with the monotonic time the segment arrived. It
|
|
// returns whether the segment should be kept (processed) or dropped.
|
|
PreRx(incoming Segment, now int64) RxDirective
|
|
|
|
// PreTx is called on entering the transmit path (Encapsulate), before a
|
|
// segment is built, with the current monotonic time. Its directive tells the
|
|
// connection whether to retransmit unacknowledged data, rewind the send
|
|
// pointer, or hold back new data.
|
|
PreTx(now int64) TxDirective
|
|
|
|
// PostTx is called on leaving the transmit path with the segment that was
|
|
// actually emitted and the monotonic time it was sent. This is where segment
|
|
// timing (for RTT sampling and the retransmission timer) is recorded.
|
|
PostTx(outgoing Segment, now int64)
|
|
}
|
|
|
|
// TxDirective is returned by [LossRecovery.PreTx] to steer the transmit path.
|
|
// The zero value directs the connection to proceed normally (send new data if
|
|
// available, no retransmission).
|
|
type TxDirective struct {
|
|
// RewindNXT is the number of sequence-space octets to rewind snd.NXT by
|
|
// before transmitting, for partial (e.g. selective) retransmission. Zero
|
|
// means no rewind. It is independent of Retransmit, which rewinds fully to
|
|
// snd.UNA.
|
|
// RewindNXT uint32
|
|
|
|
// RetransmitAll requests go-back-N retransmission: the connection rewinds
|
|
// snd.NXT to snd.UNA and resends unacknowledged data from the oldest
|
|
// sequence number.
|
|
RetransmitAll bool
|
|
// HoldNew pauses transmission of new data (for example when the congestion
|
|
// window is exhausted). Retransmissions already directed by this same
|
|
// directive still proceed.
|
|
// HoldNew bool
|
|
}
|
|
|
|
// RxDirective is returned by [LossRecovery.PreRx].
|
|
//
|
|
// NOTE: its shape is the minimum viable contract — it mirrors the original
|
|
// PreRx "keep" boolean from discussion #157 — and is the one element of the
|
|
// interface not yet fully settled there. It is a struct (rather than a bare
|
|
// bool) so fields can be added without breaking implementations.
|
|
type RxDirective struct {
|
|
// Keep reports whether the received segment should be handed to the state
|
|
// machine. A false value drops the segment before it is processed.
|
|
Keep bool
|
|
}
|