nquic_protocol_ack (nquic v1.0.0)

View Source

ACK generation and received-packet-number bookkeeping (RFC 9000 §13.2, §19.3).

Pure functions over #conn_state{} covering received-PN range algebra (insert / merge / prune), per-space received_ranges and largest_received tracking, ECN counter accounting, ACK-frame construction, and the ack-eliciting decision that governs whether an ACK is queued. Queued ACKs drain into the per-encryption-level frame queues owned by nquic_protocol_send, which this module calls module-qualified.

Summary

Functions

Apply RFC 9000 §13.2.4 pruning to received_ranges for Space.

Drop ranges from received_ranges (descending list of {High, Low} pairs) whose entire span is at or below Threshold. The range that straddles Threshold is truncated; ranges entirely above Threshold are unchanged. Used by apply_received_ranges_prune/3 to apply RFC 9000 §13.2.4.

Increment the per-space ECN counter for the given mark.

Fused PN tracking + ECN counter update in a single pn_spaces rewrite. Replaces track_received_pn/3 followed by track_ecn_mark/3 on the recv hot path, halving the #conn_state{} record copies and the outer pn_spaces map updates. Behaviourally equivalent to calling both helpers in sequence.

Functions

apply_received_ranges_prune(Space, AckedFrames, State)

-spec apply_received_ranges_prune(nquic_packet:space(), [nquic_frame:t()], nquic_protocol:state()) ->
                                     nquic_protocol:state().

Apply RFC 9000 §13.2.4 pruning to received_ranges for Space.

AckedFrames is the flattened frame list returned by nquic_loss:on_ack_received/6 for an incoming ACK in Space. Any #ack{} frames in that list are ACKs we previously sent that the peer has now acknowledged; their largest_acknowledged value is therefore known-known on both sides, so the corresponding tracked PNs can be dropped from our received_ranges. Without this prune received_ranges grows monotonically across a connection's lifetime and inflates both ACK build cost and the work the peer does to process those ACKs.

build_ack_for_space/2

-spec build_ack_for_space(nquic_packet:space(), nquic_protocol:state()) ->
                             {ok,
                              #ack{largest_acknowledged :: nquic_packet_number:t(),
                                   delay :: non_neg_integer(),
                                   first_ack_range :: non_neg_integer(),
                                   ack_ranges ::
                                       [#ack_range{gap :: non_neg_integer(),
                                                   length :: non_neg_integer()}],
                                   ecn_counts :: term() | undefined}} |
                             none.

force_queue_ack/2

-spec force_queue_ack(application, nquic_protocol:state()) -> nquic_protocol:state().

insert_pn_range/2

is_ack_eliciting/1

-spec is_ack_eliciting([nquic_frame:t()]) -> boolean().

maybe_queue_ack(Header, Frames, State)

merge_ranges/1

prune_received_ranges/2

Drop ranges from received_ranges (descending list of {High, Low} pairs) whose entire span is at or below Threshold. The range that straddles Threshold is truncated; ranges entirely above Threshold are unchanged. Used by apply_received_ranges_prune/3 to apply RFC 9000 §13.2.4.

ranges_to_ack_ranges/2

-spec ranges_to_ack_ranges(nquic_packet_number:t(),
                           [{nquic_packet_number:t(), nquic_packet_number:t()}]) ->
                              [#ack_range{gap :: non_neg_integer(), length :: non_neg_integer()}].

track_ecn_mark/3

Increment the per-space ECN counter for the given mark.

track_received_pn/3

track_received_pn_and_ecn/4

Fused PN tracking + ECN counter update in a single pn_spaces rewrite. Replaces track_received_pn/3 followed by track_ecn_mark/3 on the recv hot path, halving the #conn_state{} record copies and the outer pn_spaces map updates. Behaviourally equivalent to calling both helpers in sequence.