nquic_protocol_ack (nquic v1.0.0)
View SourceACK 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
-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.
-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.
-spec force_queue_ack(application, nquic_protocol:state()) -> nquic_protocol:state().
-spec insert_pn_range(nquic_packet_number:t(), [{nquic_packet_number:t(), nquic_packet_number:t()}]) -> [{nquic_packet_number:t(), nquic_packet_number:t()}].
-spec is_ack_eliciting([nquic_frame:t()]) -> boolean().
-spec maybe_queue_ack(nquic_packet:header(), [nquic_frame:t()], nquic_protocol:state()) -> nquic_protocol:state().
-spec merge_ranges([{nquic_packet_number:t(), nquic_packet_number:t()}]) -> [{nquic_packet_number:t(), nquic_packet_number:t()}].
-spec prune_received_ranges([{nquic_packet_number:t(), nquic_packet_number:t()}], nquic_packet_number:t()) -> [{nquic_packet_number:t(), nquic_packet_number:t()}].
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.
-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()}].
-spec track_ecn_mark(nquic_packet:space(), nquic_socket:ecn_mark(), nquic_protocol:state()) -> nquic_protocol:state().
Increment the per-space ECN counter for the given mark.
-spec track_received_pn(nquic_packet:space(), nquic_packet_number:t(), nquic_protocol:state()) -> nquic_protocol:state().
-spec track_received_pn_and_ecn(nquic_packet:space(), nquic_packet_number:t(), nquic_socket:ecn_mark(), nquic_protocol:state()) -> nquic_protocol:state().
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.