nquic_protocol_cid (nquic v1.0.0)

View Source

Connection ID management for the QUIC protocol state.

Pure functions over #conn_state{} that handle peer CID issuance (NEW_CONNECTION_ID), retirement (RETIRE_CONNECTION_ID), local CID rotation, and DCID switching for path migration. Extracted from nquic_protocol as part of REVIEW_PLAN.md Phase 4.4.

Side effects are limited to nquic_listener:dispatch_register/3 and nquic_listener:dispatch_unregister/2 for keeping the dispatch table in sync when the connection has one set; everything else is functional state manipulation.

Summary

Functions

Issue spare NEW_CONNECTION_ID frames up to the peer's active_connection_id_limit. Both endpoints account the SCID delivered in transport parameters as a single local CID (sequence 0); peers tolerate up to limit concurrent CIDs (RFC 9000 §5.1.1). We top up the gap so a future migration has spare CIDs on both sides; without this, server-initiated migration (per-conn FDs) cannot rotate DCID and the path validation refuses to flip. No-op when remote transport parameters have not been processed yet: the limit is unknown, and the existing reactive issue_new_connection_id path picks up the slack on demand.

Functions

find_cid_seq(CID, PeerCids)

-spec find_cid_seq(nquic:connection_id(), #{non_neg_integer() => map()}) ->
                      non_neg_integer() | undefined.

handle_new_connection_id(SeqNum, RetirePriorTo, CID, Token, State)

-spec handle_new_connection_id(non_neg_integer(),
                               non_neg_integer(),
                               nquic:connection_id(),
                               binary(),
                               nquic_protocol:state()) ->
                                  {ok, nquic_protocol:state()}.

handle_retire_connection_id(SeqNum, State)

-spec handle_retire_connection_id(non_neg_integer(), nquic_protocol:state()) ->
                                     {ok, nquic_protocol:state()}.

issue_new_connection_id(State)

-spec issue_new_connection_id(nquic_protocol:state()) -> {ok, nquic_protocol:state()}.

issue_spare_cids/1

-spec issue_spare_cids(nquic_protocol:state()) -> {ok, nquic_protocol:state()}.

Issue spare NEW_CONNECTION_ID frames up to the peer's active_connection_id_limit. Both endpoints account the SCID delivered in transport parameters as a single local CID (sequence 0); peers tolerate up to limit concurrent CIDs (RFC 9000 §5.1.1). We top up the gap so a future migration has spare CIDs on both sides; without this, server-initiated migration (per-conn FDs) cannot rotate DCID and the path validation refuses to flip. No-op when remote transport parameters have not been processed yet: the limit is unknown, and the existing reactive issue_new_connection_id path picks up the slack on demand.

retire_peer_cids(RetirePriorTo, PeerCids)

-spec retire_peer_cids(non_neg_integer(), #{non_neg_integer() => map()}) ->
                          {[non_neg_integer()], #{non_neg_integer() => map()}}.

rotate_dcid/1

-spec rotate_dcid(nquic_protocol:state()) -> {ok, nquic_protocol:state()} | {error, no_available_cids}.