Files
lneto/tcp/loss.go
T
Pat Whittingslow 41c7e3c445 add loss.go (#168)
2026-07-22 13:09:12 -03:00

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
}