moonbitstack/moonquic/recovery does not have a README file

    Control

    pub(open) trait Control {
    fn window(Self) -> Int64
    fn in_flight(Self) -> Int64
    fn on_sent(Self, Int64) -> Unit
    fn on_ack(Self, Int64) -> Unit
    fn on_lost(Self, Int64) -> Unit
    fn on_congestion(Self, at~ : Int64, now~ : Int64) -> Unit
    fn on_persistent(Self) -> Unit
    }

    A congestion controller (RFC 9002 §7): how much may be in flight, and what to make of each packet sent, acknowledged or lost.

    NewReno is the one RFC 9002 specifies, and the reason this is a trait rather than that struct is §7's own opening — an endpoint may use any controller, and Cubic and BBR answer the same questions. Implementing this is all it takes; nothing here changes.

    Flight

    pub struct Flight {
    packets : Array[Sent]
    largest_acked : Int64
    }

    What is outstanding in one packet-number space, and the largest number acknowledged so far — -1 before any ACK has arrived.

    Flight::largest_acked

    fn Flight::largest_acked(self : Flight) -> Int64

    The largest packet number acknowledged, or -1 before any ACK.

    Flight::lost

    fn Flight::lost(self : Flight, now : Int64, packets~ : Int64, time~ : Int64) -> Array[Sent]

    Declare lost every outstanding packet that either sits at least packets behind the largest acknowledged (RFC 9002 §6.1.1) or was sent longer than time ago while a later packet has been acknowledged (§6.1.2), and stop tracking them.

    The records come back whole, sizes included, because the congestion controller has to take those bytes out of flight and only the caller knows which controller that is.

    Flight::new

    fn Flight::new() -> Flight

    A fresh flight, with nothing outstanding.

    Flight::on_ack

    fn Flight::on_ack(self : Flight, ranges : Array[(Int64, Int64)]) -> Int64

    Process an ACK's acknowledged ranges: drop every outstanding packet that falls in one, advance the largest acknowledged, and answer with the bytes taken out of flight.

    Flight::on_sent

    fn Flight::on_sent(self : Flight, pn : Int64, at~ : Int64, size~ : Int64) -> Unit

    Record that an ack-eliciting packet went out.

    Flight::outstanding

    fn Flight::outstanding(self : Flight) -> Array[Int64]

    The packet numbers still outstanding.

    Flight::time_of

    fn Flight::time_of(self : Flight, pn : Int64) -> Int64?

    When the outstanding packet numbered pn was sent, or None if it is not outstanding.

    NewReno

    pub struct NewReno {
    window : Int64
    ssthresh : Int64
    in_flight : Int64
    recovery : Int64
    policy : Policy
    }

    NewReno, the controller RFC 9002 §7 specifies.

    NewReno::in_flight

    fn NewReno::in_flight(self : NewReno) -> Int64

    NewReno::minimum

    fn NewReno::minimum(self : NewReno) -> Int64

    The smallest window the controller will reduce to (RFC 9002 §7.2).

    NewReno::new

    fn NewReno::new(policy? : Policy) -> NewReno

    A fresh controller (RFC 9002 §7.2): the initial window is min(10·datagram, max(2·datagram, 14720)), the slow-start threshold is unbounded, and nothing is in flight or in recovery.

    NewReno::on_ack

    fn NewReno::on_ack(self : NewReno, size : Int64) -> Unit

    NewReno::on_congestion

    fn NewReno::on_congestion(self : NewReno, at~ : Int64, now~ : Int64) -> Unit

    NewReno::on_lost

    fn NewReno::on_lost(self : NewReno, size : Int64) -> Unit

    NewReno::on_persistent

    fn NewReno::on_persistent(self : NewReno) -> Unit

    NewReno::on_sent

    fn NewReno::on_sent(self : NewReno, size : Int64) -> Unit

    NewReno::recovering

    fn NewReno::recovering(self : NewReno, at : Int64) -> Bool

    Whether a packet sent at at falls inside the recovery period already under way.

    NewReno::ssthresh

    fn NewReno::ssthresh(self : NewReno) -> Int64

    The slow-start threshold in bytes.

    NewReno::window

    fn NewReno::window(self : NewReno) -> Int64

    Policy

    pub(all) struct Policy {
    packets : Int64
    time : Double
    granularity : Int64
    initial_rtt : Int64
    persistent : Int64
    reduction : Double
    datagram : Int64
    ack_delay : Int64
    }

    The constants RFC 9002 leaves as tunables, and the two connection parameters the timers are computed from. Every duration is microseconds and every size is bytes.

    The presets are the values the RFC itself recommends (§6.1.1, §6.1.2, §6.2.2, §7.2, §7.3, §7.6) together with RFC 9000 §18.2's default max_ack_delay and RFC 9000 §14's minimum datagram size, which is the one every path is required to carry.

    Policy::new

    fn Policy::new(packets? : Int64, time? : Double, granularity? : Int64, initial_rtt? : Int64, persistent? : Int64, reduction? : Double, datagram? : Int64, ack_delay? : Int64) -> Policy

    A policy by name, each part defaulting to RFC 9002's recommendation.

    packets is kPacketThreshold, time kTimeThreshold, granularity kGranularity, initial_rtt kInitialRtt, persistent kPersistentCongestionThreshold, reduction kLossReductionFactor. datagram is the sender's maximum datagram size and ack_delay the peer's advertised max_ack_delay, both of which a real connection learns from its transport parameters rather than keeps at the default.

    Rtt

    pub struct Rtt {
    latest : Int64
    min : Int64
    smoothed : Int64
    variation : Int64
    sampled : Bool
    }

    An endpoint's round-trip estimate for one packet-number space (RFC 9002 §5).

    Rtt::latest

    fn Rtt::latest(self : Rtt) -> Int64

    The most recent sample.

    Rtt::min

    fn Rtt::min(self : Rtt) -> Int64

    The smallest sample seen, which is the closest this endpoint has come to measuring the path itself rather than the path plus the peer's delays.

    Rtt::new

    fn Rtt::new() -> Rtt

    A fresh estimate, with no sample yet.

    Rtt::pto

    fn Rtt::pto(self : Rtt, policy? : Policy) -> Int64

    The Probe Timeout: smoothed + max(4·variation, granularity) + ack_delay (RFC 9002 §6.2.1), or twice the policy's initial RTT before the first sample (§6.2.2).

    Rtt::sample

    fn Rtt::sample(self : Rtt, latest : Int64, ack_delay~ : Int64, policy? : Policy) -> Unit

    Fold in a round-trip sample (RFC 9002 §5.3).

    ack_delay is what the peer said it waited before acknowledging; it is capped at the policy's ack_delay and subtracted only while doing so keeps the sample at or above the minimum seen, so a peer cannot talk the estimate below the path's real latency. The first sample seeds the estimate outright; later ones move the weighted average.

    Rtt::sampled

    fn Rtt::sampled(self : Rtt) -> Bool

    Whether any sample has arrived. Before the first one the timers fall back to the policy's initial RTT, which is the whole of what an endpoint knows at that point.

    Rtt::smoothed

    fn Rtt::smoothed(self : Rtt) -> Int64

    The smoothed estimate the timers are built on.

    Rtt::threshold

    fn Rtt::threshold(self : Rtt, policy? : Policy) -> Int64

    The loss time threshold: max(time · max(smoothed, latest), granularity) (RFC 9002 §6.1.2).

    Rtt::variation

    fn Rtt::variation(self : Rtt) -> Int64

    The mean deviation of the samples.

    Sent

    pub(all) struct Sent {
    pn : Int64
    at : Int64
    size : Int64
    } derive(Eq,
    Debug
    )

    A sent, not yet acknowledged ack-eliciting packet (RFC 9002 §A.1): its number, when it went out, and how many bytes it put in flight.

    Sent::equal

    fn Sent::equal(Sent, Sent) -> Bool

    Sent::not_equal

    fn Sent::not_equal(x : Sent, y : Sent) -> Bool

    Sent::to_repr

    State

    pub struct State {
    rtt : Rtt
    flight : Flight
    control : &Control
    policy : Policy
    pto_count : Int
    last_sent : Int64
    }

    A sender's recovery state for one packet-number space: the round-trip estimate, what is outstanding, and the congestion controller, driven by the two events a sender has — a packet went out, an ACK came back.

    State::can_send

    fn State::can_send(self : State, bytes : Int64) -> Bool

    Whether bytes more may go out without exceeding the congestion window.

    State::in_flight

    fn State::in_flight(self : State) -> Int64

    The bytes currently in flight.

    State::new

    fn State::new(policy? : Policy, control? : &Control) -> State

    A fresh state. Leave control out for NewReno under the same policy; give one to use another controller.

    State::on_ack

    fn State::on_ack(self : State, frame :
    Frame
    , now : Int64, ack_delay~ : Int64) -> Array[Int64] raise
    Refused

    An ACK arrived (RFC 9002 §5–§7): sample the round trip off the largest newly acknowledged packet, free the acknowledged bytes, then run loss detection over both thresholds. Answers with the packet numbers declared lost — the frames to send again.

    ack_delay is what the ACK frame said, in microseconds; the frame's own field is in the peer's exponent and decoding it is the connection's job, not this one's.

    One round of loss is one congestion signal however many packets it covers, and a round spanning more than persistent probe timeouts is persistent congestion (§7.6).

    State::on_pto

    fn State::on_pto(self : State) -> Unit

    The probe timer fired (RFC 9002 §6.2.4): back off for the next arming. Sending the probes is the caller's, because what to put in them is the connection's business.

    State::on_sent

    fn State::on_sent(self : State, pn : Int64, at~ : Int64, size~ : Int64) -> Unit

    An ack-eliciting packet went out: track it for acknowledgement and charge the window.

    State::outstanding

    fn State::outstanding(self : State) -> Array[Int64]

    The packet numbers still outstanding.

    State::pto

    fn State::pto(self : State) -> Int64

    The probe timeout in microseconds, before backoff.

    State::pto_count

    fn State::pto_count(self : State) -> Int

    How many probe timeouts have fired without an acknowledgement since the last one that did — the backoff exponent.

    State::pto_deadline

    fn State::pto_deadline(self : State) -> Int64?

    When the probe timer fires: the last ack-eliciting packet's send time plus the timeout backed off by 2^pto_count (RFC 9002 §6.2.1). None when nothing is outstanding, which is the timer disarmed.

    State::rtt

    fn State::rtt(self : State) -> Rtt

    The round-trip estimate this space has built.

    State::window

    fn State::window(self : State) -> Int64

    The congestion window in bytes.

    can_send

    fn can_send(control : &Control, bytes : Int64) -> Bool

    Whether bytes more fit in the window.

    policy

    let policy : Policy

    RFC 9002's recommended constants.

    Source Files