nquic_flow (nquic v1.0.0)

View Source

Connection and stream flow control per RFC 9000 Section 4.

Enforces data limits at both connection and stream levels. Tracks the highest byte offset seen (recv_max_offset) separately from contiguous bytes delivered to the application (recv_offset). Generates MAX_DATA and MAX_STREAM_DATA frames when the available window drops below half the configured size.

Summary

Functions

Check if connection-level flow control allows sending the given number of bytes.

Check if stream-level flow control allows sending the given number of bytes.

Initialize connection-level send and receive limits from transport parameters.

Initialize stream-level send and receive limits based on stream type and transport parameters.

Generate a MAX_DATA frame if the connection receive window is below half the target size.

Generate a MAX_STREAM_DATA frame if the stream receive window is below half the target size.

Update receive offsets after receiving data, returning an error if limits are exceeded.

Update connection and stream send offsets after sending data on a stream.

Functions

check_conn_send(ConnState, Length)

-spec check_conn_send(#conn_state{role :: client | server,
                                  scid :: nquic:connection_id(),
                                  dcid :: nquic:connection_id(),
                                  odcid :: nquic:connection_id() | undefined,
                                  retry_scid :: nquic:connection_id() | undefined,
                                  retry_token :: binary(),
                                  version :: non_neg_integer(),
                                  version_preference :: [non_neg_integer()],
                                  socket :: nquic_socket:t() | undefined,
                                  peer :: nquic_socket:sockaddr() | undefined,
                                  select_info :: nquic_socket:select_info() | undefined,
                                  pn_spaces :: #{nquic_packet:space() => map()},
                                  app_next_pn :: non_neg_integer(),
                                  app_largest_received :: integer(),
                                  loss_state :: nquic_loss:loss_state() | undefined,
                                  dispatch_table :: nquic_dispatch:t() | undefined,
                                  listener :: pid() | undefined,
                                  connect_waiters :: [gen_server:from()],
                                  local_params ::
                                      #transport_params{original_destination_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        max_idle_timeout :: non_neg_integer(),
                                                        stateless_reset_token :: binary() | undefined,
                                                        max_udp_payload_size :: pos_integer(),
                                                        initial_max_data :: non_neg_integer(),
                                                        initial_max_stream_data_bidi_local ::
                                                            non_neg_integer(),
                                                        initial_max_stream_data_bidi_remote ::
                                                            non_neg_integer(),
                                                        initial_max_stream_data_uni :: non_neg_integer(),
                                                        initial_max_streams_bidi :: non_neg_integer(),
                                                        initial_max_streams_uni :: non_neg_integer(),
                                                        ack_delay_exponent :: 0..20,
                                                        max_ack_delay :: non_neg_integer(),
                                                        disable_active_migration :: boolean(),
                                                        preferred_address ::
                                                            nquic_transport:preferred_address() |
                                                            undefined,
                                                        active_connection_id_limit :: non_neg_integer(),
                                                        initial_source_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        retry_source_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        version_information ::
                                                            nquic_transport:version_information() |
                                                            undefined,
                                                        max_datagram_frame_size ::
                                                            non_neg_integer() | undefined},
                                  remote_params ::
                                      #transport_params{original_destination_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        max_idle_timeout :: non_neg_integer(),
                                                        stateless_reset_token :: binary() | undefined,
                                                        max_udp_payload_size :: pos_integer(),
                                                        initial_max_data :: non_neg_integer(),
                                                        initial_max_stream_data_bidi_local ::
                                                            non_neg_integer(),
                                                        initial_max_stream_data_bidi_remote ::
                                                            non_neg_integer(),
                                                        initial_max_stream_data_uni :: non_neg_integer(),
                                                        initial_max_streams_bidi :: non_neg_integer(),
                                                        initial_max_streams_uni :: non_neg_integer(),
                                                        ack_delay_exponent :: 0..20,
                                                        max_ack_delay :: non_neg_integer(),
                                                        disable_active_migration :: boolean(),
                                                        preferred_address ::
                                                            nquic_transport:preferred_address() |
                                                            undefined,
                                                        active_connection_id_limit :: non_neg_integer(),
                                                        initial_source_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        retry_source_connection_id ::
                                                            nquic:connection_id() | undefined,
                                                        version_information ::
                                                            nquic_transport:version_information() |
                                                            undefined,
                                                        max_datagram_frame_size ::
                                                            non_neg_integer() | undefined} |
                                      undefined,
                                  server_packet_processed :: boolean(),
                                  owner :: pid() | undefined,
                                  owner_mon :: reference() | undefined,
                                  deferred_flush_pending :: boolean(),
                                  pending_ack_count :: non_neg_integer(),
                                  last_idle_ms :: non_neg_integer() | infinity | undefined,
                                  last_pto_ms :: non_neg_integer() | cancel | undefined,
                                  recv_ecn :: nquic_socket:ecn_mark(),
                                  pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                  gso_size :: undefined | pos_integer(),
                                  max_payload_size :: pos_integer(),
                                  server_per_conn_fd :: boolean(),
                                  proactive_cids :: boolean(),
                                  socket_connected :: boolean(),
                                  self_migration_pending :: boolean(),
                                  metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                  spin_enabled :: boolean(),
                                  peer_spin :: 0..1,
                                  new_token_enabled :: boolean(),
                                  new_token_lifetime :: pos_integer(),
                                  qlog :: undefined | nquic_qlog:qlog_state(),
                                  close_kind :: undefined | local | peer | idle_timeout | protocol_error,
                                  crypto ::
                                      #conn_crypto{tls_state :: term(),
                                                   keys :: #{nquic_packet:space() | rtt0 => map()},
                                                   app_send_keys :: map() | undefined,
                                                   app_recv_keys :: map() | undefined,
                                                   crypto_buffer ::
                                                       #{nquic_packet:space() =>
                                                             {non_neg_integer(), binary(), list()}},
                                                   cipher ::
                                                       aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                                                   cipher_suites ::
                                                       [aes_128_gcm | aes_256_gcm | chacha20_poly1305] |
                                                       undefined,
                                                   key_phase :: boolean(),
                                                   key_update_pending :: boolean(),
                                                   client_app_secret :: binary() | undefined,
                                                   server_app_secret :: binary() | undefined,
                                                   old_read_keys ::
                                                       #{key := binary(), iv := binary()} | undefined,
                                                   zero_rtt_accepted :: boolean(),
                                                   replay_protection :: module() | undefined,
                                                   session_ticket :: map() | undefined,
                                                   resumption_secret :: binary() | undefined,
                                                   session_cache ::
                                                       atom() | false | {module, module()} | undefined,
                                                   token_cache :: atom() | false | {module, module()},
                                                   alpn :: [binary()] | undefined,
                                                   hostname :: string() | binary() | undefined,
                                                   cert :: binary() | undefined,
                                                   cert_chain :: [binary()],
                                                   key :: any() | undefined,
                                                   verify :: verify_none | verify_peer,
                                                   cacerts :: [binary()],
                                                   peer_cert :: binary() | undefined,
                                                   static_key :: binary() | undefined},
                                  streams_state ::
                                      #conn_streams{streams ::
                                                        #{nquic:stream_id() =>
                                                              #stream_state{stream_id ::
                                                                                nquic:stream_id(),
                                                                            type :: bidi | uni,
                                                                            send_state ::
                                                                                ready | send |
                                                                                data_sent | data_recvd |
                                                                                reset_sent | reset_recvd,
                                                                            send_offset ::
                                                                                non_neg_integer(),
                                                                            send_max_data ::
                                                                                non_neg_integer(),
                                                                            last_stream_data_blocked ::
                                                                                non_neg_integer(),
                                                                            pending_send_data ::
                                                                                [binary()],
                                                                            pending_send_size ::
                                                                                non_neg_integer(),
                                                                            pending_send_fin ::
                                                                                boolean(),
                                                                            recv_state ::
                                                                                recv | size_known |
                                                                                data_recvd |
                                                                                reset_recvd |
                                                                                data_read | reset_read,
                                                                            recv_offset ::
                                                                                non_neg_integer(),
                                                                            recv_max_offset ::
                                                                                non_neg_integer(),
                                                                            recv_window ::
                                                                                non_neg_integer(),
                                                                            recv_buffer ::
                                                                                gb_trees:tree(non_neg_integer(),
                                                                                              {binary(),
                                                                                               boolean()}),
                                                                            app_buffer :: iodata(),
                                                                            app_buffer_size ::
                                                                                non_neg_integer()}},
                                                    next_bidi_stream :: nquic:stream_id() | undefined,
                                                    next_uni_stream :: nquic:stream_id() | undefined,
                                                    peer_max_streams_bidi :: non_neg_integer(),
                                                    peer_max_streams_uni :: non_neg_integer(),
                                                    local_max_streams_bidi :: non_neg_integer(),
                                                    local_max_streams_uni :: non_neg_integer(),
                                                    last_sent_max_streams_bidi :: non_neg_integer(),
                                                    last_sent_max_streams_uni :: non_neg_integer(),
                                                    max_peer_bidi_stream_id ::
                                                        non_neg_integer() | undefined,
                                                    max_peer_uni_stream_id ::
                                                        non_neg_integer() | undefined,
                                                    opened_peer_bidi_count :: non_neg_integer(),
                                                    opened_peer_uni_count :: non_neg_integer(),
                                                    closed_peer_bidi_wm :: integer(),
                                                    closed_peer_uni_wm :: integer(),
                                                    closed_peer_streams :: #{nquic:stream_id() => true},
                                                    recv_waiters ::
                                                        #{nquic:stream_id() => gen_statem:from()},
                                                    accept_stream_waiters ::
                                                        queue:queue(gen_statem:from()),
                                                    pending_streams :: queue:queue(nquic:stream_id()),
                                                    blocked_streams :: #{nquic:stream_id() => true},
                                                    pending_send_streams :: #{nquic:stream_id() => true},
                                                    send_buffer_high_water :: pos_integer(),
                                                    send_timeout :: timeout(),
                                                    send_waiters ::
                                                        queue:queue(nquic_conn_send_waiters:t())},
                                  flow ::
                                      #conn_flow{local_max_data :: non_neg_integer(),
                                                 remote_max_data :: non_neg_integer(),
                                                 data_sent :: non_neg_integer(),
                                                 data_received :: non_neg_integer(),
                                                 last_data_blocked :: non_neg_integer(),
                                                 pending_initial_frames :: [nquic_frame:t()],
                                                 pending_handshake_frames :: [nquic_frame:t()],
                                                 pending_app_frames :: [nquic_frame:t()],
                                                 pending_app_pre_encoded ::
                                                     [{non_neg_integer(), iodata(), nquic_frame:t()}],
                                                 queued_app_send_bytes :: non_neg_integer()},
                                  path ::
                                      #conn_path_mgmt{path_state :: nquic_path:state() | undefined,
                                                      peer_cids ::
                                                          #{non_neg_integer() =>
                                                                #{cid := nquic:connection_id(),
                                                                  token := binary()}},
                                                      local_cids ::
                                                          #{non_neg_integer() => nquic:connection_id()},
                                                      local_cid_seq :: non_neg_integer(),
                                                      peer_retire_prior_to :: non_neg_integer(),
                                                      anti_amp_bytes_received :: non_neg_integer(),
                                                      anti_amp_bytes_sent :: non_neg_integer(),
                                                      address_validated :: boolean()}},
                      non_neg_integer()) ->
                         ok | {blocked, non_neg_integer()}.

Check if connection-level flow control allows sending the given number of bytes.

check_stream_send(StreamState, Length)

-spec check_stream_send(#stream_state{stream_id :: nquic:stream_id(),
                                      type :: bidi | uni,
                                      send_state ::
                                          ready | send | data_sent | data_recvd | reset_sent |
                                          reset_recvd,
                                      send_offset :: non_neg_integer(),
                                      send_max_data :: non_neg_integer(),
                                      last_stream_data_blocked :: non_neg_integer(),
                                      pending_send_data :: [binary()],
                                      pending_send_size :: non_neg_integer(),
                                      pending_send_fin :: boolean(),
                                      recv_state ::
                                          recv | size_known | data_recvd | reset_recvd | data_read |
                                          reset_read,
                                      recv_offset :: non_neg_integer(),
                                      recv_max_offset :: non_neg_integer(),
                                      recv_window :: non_neg_integer(),
                                      recv_buffer ::
                                          gb_trees:tree(non_neg_integer(), {binary(), boolean()}),
                                      app_buffer :: iodata(),
                                      app_buffer_size :: non_neg_integer()},
                        non_neg_integer()) ->
                           ok | {blocked, non_neg_integer()}.

Check if stream-level flow control allows sending the given number of bytes.

init_conn_limits(ConnState)

-spec init_conn_limits(#conn_state{role :: client | server,
                                   scid :: nquic:connection_id(),
                                   dcid :: nquic:connection_id(),
                                   odcid :: nquic:connection_id() | undefined,
                                   retry_scid :: nquic:connection_id() | undefined,
                                   retry_token :: binary(),
                                   version :: non_neg_integer(),
                                   version_preference :: [non_neg_integer()],
                                   socket :: nquic_socket:t() | undefined,
                                   peer :: nquic_socket:sockaddr() | undefined,
                                   select_info :: nquic_socket:select_info() | undefined,
                                   pn_spaces :: #{nquic_packet:space() => map()},
                                   app_next_pn :: non_neg_integer(),
                                   app_largest_received :: integer(),
                                   loss_state :: nquic_loss:loss_state() | undefined,
                                   dispatch_table :: nquic_dispatch:t() | undefined,
                                   listener :: pid() | undefined,
                                   connect_waiters :: [gen_server:from()],
                                   local_params ::
                                       #transport_params{original_destination_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         max_idle_timeout :: non_neg_integer(),
                                                         stateless_reset_token :: binary() | undefined,
                                                         max_udp_payload_size :: pos_integer(),
                                                         initial_max_data :: non_neg_integer(),
                                                         initial_max_stream_data_bidi_local ::
                                                             non_neg_integer(),
                                                         initial_max_stream_data_bidi_remote ::
                                                             non_neg_integer(),
                                                         initial_max_stream_data_uni ::
                                                             non_neg_integer(),
                                                         initial_max_streams_bidi :: non_neg_integer(),
                                                         initial_max_streams_uni :: non_neg_integer(),
                                                         ack_delay_exponent :: 0..20,
                                                         max_ack_delay :: non_neg_integer(),
                                                         disable_active_migration :: boolean(),
                                                         preferred_address ::
                                                             nquic_transport:preferred_address() |
                                                             undefined,
                                                         active_connection_id_limit :: non_neg_integer(),
                                                         initial_source_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         retry_source_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         version_information ::
                                                             nquic_transport:version_information() |
                                                             undefined,
                                                         max_datagram_frame_size ::
                                                             non_neg_integer() | undefined},
                                   remote_params ::
                                       #transport_params{original_destination_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         max_idle_timeout :: non_neg_integer(),
                                                         stateless_reset_token :: binary() | undefined,
                                                         max_udp_payload_size :: pos_integer(),
                                                         initial_max_data :: non_neg_integer(),
                                                         initial_max_stream_data_bidi_local ::
                                                             non_neg_integer(),
                                                         initial_max_stream_data_bidi_remote ::
                                                             non_neg_integer(),
                                                         initial_max_stream_data_uni ::
                                                             non_neg_integer(),
                                                         initial_max_streams_bidi :: non_neg_integer(),
                                                         initial_max_streams_uni :: non_neg_integer(),
                                                         ack_delay_exponent :: 0..20,
                                                         max_ack_delay :: non_neg_integer(),
                                                         disable_active_migration :: boolean(),
                                                         preferred_address ::
                                                             nquic_transport:preferred_address() |
                                                             undefined,
                                                         active_connection_id_limit :: non_neg_integer(),
                                                         initial_source_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         retry_source_connection_id ::
                                                             nquic:connection_id() | undefined,
                                                         version_information ::
                                                             nquic_transport:version_information() |
                                                             undefined,
                                                         max_datagram_frame_size ::
                                                             non_neg_integer() | undefined} |
                                       undefined,
                                   server_packet_processed :: boolean(),
                                   owner :: pid() | undefined,
                                   owner_mon :: reference() | undefined,
                                   deferred_flush_pending :: boolean(),
                                   pending_ack_count :: non_neg_integer(),
                                   last_idle_ms :: non_neg_integer() | infinity | undefined,
                                   last_pto_ms :: non_neg_integer() | cancel | undefined,
                                   recv_ecn :: nquic_socket:ecn_mark(),
                                   pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                   gso_size :: undefined | pos_integer(),
                                   max_payload_size :: pos_integer(),
                                   server_per_conn_fd :: boolean(),
                                   proactive_cids :: boolean(),
                                   socket_connected :: boolean(),
                                   self_migration_pending :: boolean(),
                                   metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                   spin_enabled :: boolean(),
                                   peer_spin :: 0..1,
                                   new_token_enabled :: boolean(),
                                   new_token_lifetime :: pos_integer(),
                                   qlog :: undefined | nquic_qlog:qlog_state(),
                                   close_kind ::
                                       undefined | local | peer | idle_timeout | protocol_error,
                                   crypto ::
                                       #conn_crypto{tls_state :: term(),
                                                    keys :: #{nquic_packet:space() | rtt0 => map()},
                                                    app_send_keys :: map() | undefined,
                                                    app_recv_keys :: map() | undefined,
                                                    crypto_buffer ::
                                                        #{nquic_packet:space() =>
                                                              {non_neg_integer(), binary(), list()}},
                                                    cipher ::
                                                        aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                                                    cipher_suites ::
                                                        [aes_128_gcm | aes_256_gcm | chacha20_poly1305] |
                                                        undefined,
                                                    key_phase :: boolean(),
                                                    key_update_pending :: boolean(),
                                                    client_app_secret :: binary() | undefined,
                                                    server_app_secret :: binary() | undefined,
                                                    old_read_keys ::
                                                        #{key := binary(), iv := binary()} | undefined,
                                                    zero_rtt_accepted :: boolean(),
                                                    replay_protection :: module() | undefined,
                                                    session_ticket :: map() | undefined,
                                                    resumption_secret :: binary() | undefined,
                                                    session_cache ::
                                                        atom() | false | {module, module()} | undefined,
                                                    token_cache :: atom() | false | {module, module()},
                                                    alpn :: [binary()] | undefined,
                                                    hostname :: string() | binary() | undefined,
                                                    cert :: binary() | undefined,
                                                    cert_chain :: [binary()],
                                                    key :: any() | undefined,
                                                    verify :: verify_none | verify_peer,
                                                    cacerts :: [binary()],
                                                    peer_cert :: binary() | undefined,
                                                    static_key :: binary() | undefined},
                                   streams_state ::
                                       #conn_streams{streams ::
                                                         #{nquic:stream_id() =>
                                                               #stream_state{stream_id ::
                                                                                 nquic:stream_id(),
                                                                             type :: bidi | uni,
                                                                             send_state ::
                                                                                 ready | send |
                                                                                 data_sent |
                                                                                 data_recvd |
                                                                                 reset_sent |
                                                                                 reset_recvd,
                                                                             send_offset ::
                                                                                 non_neg_integer(),
                                                                             send_max_data ::
                                                                                 non_neg_integer(),
                                                                             last_stream_data_blocked ::
                                                                                 non_neg_integer(),
                                                                             pending_send_data ::
                                                                                 [binary()],
                                                                             pending_send_size ::
                                                                                 non_neg_integer(),
                                                                             pending_send_fin ::
                                                                                 boolean(),
                                                                             recv_state ::
                                                                                 recv | size_known |
                                                                                 data_recvd |
                                                                                 reset_recvd |
                                                                                 data_read | reset_read,
                                                                             recv_offset ::
                                                                                 non_neg_integer(),
                                                                             recv_max_offset ::
                                                                                 non_neg_integer(),
                                                                             recv_window ::
                                                                                 non_neg_integer(),
                                                                             recv_buffer ::
                                                                                 gb_trees:tree(non_neg_integer(),
                                                                                               {binary(),
                                                                                                boolean()}),
                                                                             app_buffer :: iodata(),
                                                                             app_buffer_size ::
                                                                                 non_neg_integer()}},
                                                     next_bidi_stream :: nquic:stream_id() | undefined,
                                                     next_uni_stream :: nquic:stream_id() | undefined,
                                                     peer_max_streams_bidi :: non_neg_integer(),
                                                     peer_max_streams_uni :: non_neg_integer(),
                                                     local_max_streams_bidi :: non_neg_integer(),
                                                     local_max_streams_uni :: non_neg_integer(),
                                                     last_sent_max_streams_bidi :: non_neg_integer(),
                                                     last_sent_max_streams_uni :: non_neg_integer(),
                                                     max_peer_bidi_stream_id ::
                                                         non_neg_integer() | undefined,
                                                     max_peer_uni_stream_id ::
                                                         non_neg_integer() | undefined,
                                                     opened_peer_bidi_count :: non_neg_integer(),
                                                     opened_peer_uni_count :: non_neg_integer(),
                                                     closed_peer_bidi_wm :: integer(),
                                                     closed_peer_uni_wm :: integer(),
                                                     closed_peer_streams :: #{nquic:stream_id() => true},
                                                     recv_waiters ::
                                                         #{nquic:stream_id() => gen_statem:from()},
                                                     accept_stream_waiters ::
                                                         queue:queue(gen_statem:from()),
                                                     pending_streams :: queue:queue(nquic:stream_id()),
                                                     blocked_streams :: #{nquic:stream_id() => true},
                                                     pending_send_streams ::
                                                         #{nquic:stream_id() => true},
                                                     send_buffer_high_water :: pos_integer(),
                                                     send_timeout :: timeout(),
                                                     send_waiters ::
                                                         queue:queue(nquic_conn_send_waiters:t())},
                                   flow ::
                                       #conn_flow{local_max_data :: non_neg_integer(),
                                                  remote_max_data :: non_neg_integer(),
                                                  data_sent :: non_neg_integer(),
                                                  data_received :: non_neg_integer(),
                                                  last_data_blocked :: non_neg_integer(),
                                                  pending_initial_frames :: [nquic_frame:t()],
                                                  pending_handshake_frames :: [nquic_frame:t()],
                                                  pending_app_frames :: [nquic_frame:t()],
                                                  pending_app_pre_encoded ::
                                                      [{non_neg_integer(), iodata(), nquic_frame:t()}],
                                                  queued_app_send_bytes :: non_neg_integer()},
                                   path ::
                                       #conn_path_mgmt{path_state :: nquic_path:state() | undefined,
                                                       peer_cids ::
                                                           #{non_neg_integer() =>
                                                                 #{cid := nquic:connection_id(),
                                                                   token := binary()}},
                                                       local_cids ::
                                                           #{non_neg_integer() => nquic:connection_id()},
                                                       local_cid_seq :: non_neg_integer(),
                                                       peer_retire_prior_to :: non_neg_integer(),
                                                       anti_amp_bytes_received :: non_neg_integer(),
                                                       anti_amp_bytes_sent :: non_neg_integer(),
                                                       address_validated :: boolean()}}) ->
                          #conn_state{role :: client | server,
                                      scid :: nquic:connection_id(),
                                      dcid :: nquic:connection_id(),
                                      odcid :: nquic:connection_id() | undefined,
                                      retry_scid :: nquic:connection_id() | undefined,
                                      retry_token :: binary(),
                                      version :: non_neg_integer(),
                                      version_preference :: [non_neg_integer()],
                                      socket :: nquic_socket:t() | undefined,
                                      peer :: nquic_socket:sockaddr() | undefined,
                                      select_info :: nquic_socket:select_info() | undefined,
                                      pn_spaces :: #{nquic_packet:space() => map()},
                                      app_next_pn :: non_neg_integer(),
                                      app_largest_received :: integer(),
                                      loss_state :: nquic_loss:loss_state() | undefined,
                                      dispatch_table :: nquic_dispatch:t() | undefined,
                                      listener :: pid() | undefined,
                                      connect_waiters :: [gen_server:from()],
                                      local_params ::
                                          #transport_params{original_destination_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            max_idle_timeout :: non_neg_integer(),
                                                            stateless_reset_token ::
                                                                binary() | undefined,
                                                            max_udp_payload_size :: pos_integer(),
                                                            initial_max_data :: non_neg_integer(),
                                                            initial_max_stream_data_bidi_local ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_bidi_remote ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_uni ::
                                                                non_neg_integer(),
                                                            initial_max_streams_bidi ::
                                                                non_neg_integer(),
                                                            initial_max_streams_uni :: non_neg_integer(),
                                                            ack_delay_exponent :: 0..20,
                                                            max_ack_delay :: non_neg_integer(),
                                                            disable_active_migration :: boolean(),
                                                            preferred_address ::
                                                                nquic_transport:preferred_address() |
                                                                undefined,
                                                            active_connection_id_limit ::
                                                                non_neg_integer(),
                                                            initial_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            retry_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            version_information ::
                                                                nquic_transport:version_information() |
                                                                undefined,
                                                            max_datagram_frame_size ::
                                                                non_neg_integer() | undefined},
                                      remote_params ::
                                          #transport_params{original_destination_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            max_idle_timeout :: non_neg_integer(),
                                                            stateless_reset_token ::
                                                                binary() | undefined,
                                                            max_udp_payload_size :: pos_integer(),
                                                            initial_max_data :: non_neg_integer(),
                                                            initial_max_stream_data_bidi_local ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_bidi_remote ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_uni ::
                                                                non_neg_integer(),
                                                            initial_max_streams_bidi ::
                                                                non_neg_integer(),
                                                            initial_max_streams_uni :: non_neg_integer(),
                                                            ack_delay_exponent :: 0..20,
                                                            max_ack_delay :: non_neg_integer(),
                                                            disable_active_migration :: boolean(),
                                                            preferred_address ::
                                                                nquic_transport:preferred_address() |
                                                                undefined,
                                                            active_connection_id_limit ::
                                                                non_neg_integer(),
                                                            initial_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            retry_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            version_information ::
                                                                nquic_transport:version_information() |
                                                                undefined,
                                                            max_datagram_frame_size ::
                                                                non_neg_integer() | undefined} |
                                          undefined,
                                      server_packet_processed :: boolean(),
                                      owner :: pid() | undefined,
                                      owner_mon :: reference() | undefined,
                                      deferred_flush_pending :: boolean(),
                                      pending_ack_count :: non_neg_integer(),
                                      last_idle_ms :: non_neg_integer() | infinity | undefined,
                                      last_pto_ms :: non_neg_integer() | cancel | undefined,
                                      recv_ecn :: nquic_socket:ecn_mark(),
                                      pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                      gso_size :: undefined | pos_integer(),
                                      max_payload_size :: pos_integer(),
                                      server_per_conn_fd :: boolean(),
                                      proactive_cids :: boolean(),
                                      socket_connected :: boolean(),
                                      self_migration_pending :: boolean(),
                                      metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                      spin_enabled :: boolean(),
                                      peer_spin :: 0..1,
                                      new_token_enabled :: boolean(),
                                      new_token_lifetime :: pos_integer(),
                                      qlog :: undefined | nquic_qlog:qlog_state(),
                                      close_kind ::
                                          undefined | local | peer | idle_timeout | protocol_error,
                                      crypto ::
                                          #conn_crypto{tls_state :: term(),
                                                       keys :: #{nquic_packet:space() | rtt0 => map()},
                                                       app_send_keys :: map() | undefined,
                                                       app_recv_keys :: map() | undefined,
                                                       crypto_buffer ::
                                                           #{nquic_packet:space() =>
                                                                 {non_neg_integer(), binary(), list()}},
                                                       cipher ::
                                                           aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                                                       cipher_suites ::
                                                           [aes_128_gcm | aes_256_gcm |
                                                            chacha20_poly1305] |
                                                           undefined,
                                                       key_phase :: boolean(),
                                                       key_update_pending :: boolean(),
                                                       client_app_secret :: binary() | undefined,
                                                       server_app_secret :: binary() | undefined,
                                                       old_read_keys ::
                                                           #{key := binary(), iv := binary()} |
                                                           undefined,
                                                       zero_rtt_accepted :: boolean(),
                                                       replay_protection :: module() | undefined,
                                                       session_ticket :: map() | undefined,
                                                       resumption_secret :: binary() | undefined,
                                                       session_cache ::
                                                           atom() |
                                                           false |
                                                           {module, module()} |
                                                           undefined,
                                                       token_cache ::
                                                           atom() | false | {module, module()},
                                                       alpn :: [binary()] | undefined,
                                                       hostname :: string() | binary() | undefined,
                                                       cert :: binary() | undefined,
                                                       cert_chain :: [binary()],
                                                       key :: any() | undefined,
                                                       verify :: verify_none | verify_peer,
                                                       cacerts :: [binary()],
                                                       peer_cert :: binary() | undefined,
                                                       static_key :: binary() | undefined},
                                      streams_state ::
                                          #conn_streams{streams ::
                                                            #{nquic:stream_id() =>
                                                                  #stream_state{stream_id ::
                                                                                    nquic:stream_id(),
                                                                                type :: bidi | uni,
                                                                                send_state ::
                                                                                    ready | send |
                                                                                    data_sent |
                                                                                    data_recvd |
                                                                                    reset_sent |
                                                                                    reset_recvd,
                                                                                send_offset ::
                                                                                    non_neg_integer(),
                                                                                send_max_data ::
                                                                                    non_neg_integer(),
                                                                                last_stream_data_blocked ::
                                                                                    non_neg_integer(),
                                                                                pending_send_data ::
                                                                                    [binary()],
                                                                                pending_send_size ::
                                                                                    non_neg_integer(),
                                                                                pending_send_fin ::
                                                                                    boolean(),
                                                                                recv_state ::
                                                                                    recv | size_known |
                                                                                    data_recvd |
                                                                                    reset_recvd |
                                                                                    data_read |
                                                                                    reset_read,
                                                                                recv_offset ::
                                                                                    non_neg_integer(),
                                                                                recv_max_offset ::
                                                                                    non_neg_integer(),
                                                                                recv_window ::
                                                                                    non_neg_integer(),
                                                                                recv_buffer ::
                                                                                    gb_trees:tree(non_neg_integer(),
                                                                                                  {binary(),
                                                                                                   boolean()}),
                                                                                app_buffer :: iodata(),
                                                                                app_buffer_size ::
                                                                                    non_neg_integer()}},
                                                        next_bidi_stream ::
                                                            nquic:stream_id() | undefined,
                                                        next_uni_stream :: nquic:stream_id() | undefined,
                                                        peer_max_streams_bidi :: non_neg_integer(),
                                                        peer_max_streams_uni :: non_neg_integer(),
                                                        local_max_streams_bidi :: non_neg_integer(),
                                                        local_max_streams_uni :: non_neg_integer(),
                                                        last_sent_max_streams_bidi :: non_neg_integer(),
                                                        last_sent_max_streams_uni :: non_neg_integer(),
                                                        max_peer_bidi_stream_id ::
                                                            non_neg_integer() | undefined,
                                                        max_peer_uni_stream_id ::
                                                            non_neg_integer() | undefined,
                                                        opened_peer_bidi_count :: non_neg_integer(),
                                                        opened_peer_uni_count :: non_neg_integer(),
                                                        closed_peer_bidi_wm :: integer(),
                                                        closed_peer_uni_wm :: integer(),
                                                        closed_peer_streams ::
                                                            #{nquic:stream_id() => true},
                                                        recv_waiters ::
                                                            #{nquic:stream_id() => gen_statem:from()},
                                                        accept_stream_waiters ::
                                                            queue:queue(gen_statem:from()),
                                                        pending_streams ::
                                                            queue:queue(nquic:stream_id()),
                                                        blocked_streams :: #{nquic:stream_id() => true},
                                                        pending_send_streams ::
                                                            #{nquic:stream_id() => true},
                                                        send_buffer_high_water :: pos_integer(),
                                                        send_timeout :: timeout(),
                                                        send_waiters ::
                                                            queue:queue(nquic_conn_send_waiters:t())},
                                      flow ::
                                          #conn_flow{local_max_data :: non_neg_integer(),
                                                     remote_max_data :: non_neg_integer(),
                                                     data_sent :: non_neg_integer(),
                                                     data_received :: non_neg_integer(),
                                                     last_data_blocked :: non_neg_integer(),
                                                     pending_initial_frames :: [nquic_frame:t()],
                                                     pending_handshake_frames :: [nquic_frame:t()],
                                                     pending_app_frames :: [nquic_frame:t()],
                                                     pending_app_pre_encoded ::
                                                         [{non_neg_integer(), iodata(), nquic_frame:t()}],
                                                     queued_app_send_bytes :: non_neg_integer()},
                                      path ::
                                          #conn_path_mgmt{path_state :: nquic_path:state() | undefined,
                                                          peer_cids ::
                                                              #{non_neg_integer() =>
                                                                    #{cid := nquic:connection_id(),
                                                                      token := binary()}},
                                                          local_cids ::
                                                              #{non_neg_integer() =>
                                                                    nquic:connection_id()},
                                                          local_cid_seq :: non_neg_integer(),
                                                          peer_retire_prior_to :: non_neg_integer(),
                                                          anti_amp_bytes_received :: non_neg_integer(),
                                                          anti_amp_bytes_sent :: non_neg_integer(),
                                                          address_validated :: boolean()}}.

Initialize connection-level send and receive limits from transport parameters.

init_stream_limits(StreamState, ConnState, Type)

-spec init_stream_limits(#stream_state{stream_id :: nquic:stream_id(),
                                       type :: bidi | uni,
                                       send_state ::
                                           ready | send | data_sent | data_recvd | reset_sent |
                                           reset_recvd,
                                       send_offset :: non_neg_integer(),
                                       send_max_data :: non_neg_integer(),
                                       last_stream_data_blocked :: non_neg_integer(),
                                       pending_send_data :: [binary()],
                                       pending_send_size :: non_neg_integer(),
                                       pending_send_fin :: boolean(),
                                       recv_state ::
                                           recv | size_known | data_recvd | reset_recvd | data_read |
                                           reset_read,
                                       recv_offset :: non_neg_integer(),
                                       recv_max_offset :: non_neg_integer(),
                                       recv_window :: non_neg_integer(),
                                       recv_buffer ::
                                           gb_trees:tree(non_neg_integer(), {binary(), boolean()}),
                                       app_buffer :: iodata(),
                                       app_buffer_size :: non_neg_integer()},
                         #conn_state{role :: client | server,
                                     scid :: nquic:connection_id(),
                                     dcid :: nquic:connection_id(),
                                     odcid :: nquic:connection_id() | undefined,
                                     retry_scid :: nquic:connection_id() | undefined,
                                     retry_token :: binary(),
                                     version :: non_neg_integer(),
                                     version_preference :: [non_neg_integer()],
                                     socket :: nquic_socket:t() | undefined,
                                     peer :: nquic_socket:sockaddr() | undefined,
                                     select_info :: nquic_socket:select_info() | undefined,
                                     pn_spaces :: #{nquic_packet:space() => map()},
                                     app_next_pn :: non_neg_integer(),
                                     app_largest_received :: integer(),
                                     loss_state :: nquic_loss:loss_state() | undefined,
                                     dispatch_table :: nquic_dispatch:t() | undefined,
                                     listener :: pid() | undefined,
                                     connect_waiters :: [gen_server:from()],
                                     local_params ::
                                         #transport_params{original_destination_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           max_idle_timeout :: non_neg_integer(),
                                                           stateless_reset_token :: binary() | undefined,
                                                           max_udp_payload_size :: pos_integer(),
                                                           initial_max_data :: non_neg_integer(),
                                                           initial_max_stream_data_bidi_local ::
                                                               non_neg_integer(),
                                                           initial_max_stream_data_bidi_remote ::
                                                               non_neg_integer(),
                                                           initial_max_stream_data_uni ::
                                                               non_neg_integer(),
                                                           initial_max_streams_bidi :: non_neg_integer(),
                                                           initial_max_streams_uni :: non_neg_integer(),
                                                           ack_delay_exponent :: 0..20,
                                                           max_ack_delay :: non_neg_integer(),
                                                           disable_active_migration :: boolean(),
                                                           preferred_address ::
                                                               nquic_transport:preferred_address() |
                                                               undefined,
                                                           active_connection_id_limit ::
                                                               non_neg_integer(),
                                                           initial_source_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           retry_source_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           version_information ::
                                                               nquic_transport:version_information() |
                                                               undefined,
                                                           max_datagram_frame_size ::
                                                               non_neg_integer() | undefined},
                                     remote_params ::
                                         #transport_params{original_destination_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           max_idle_timeout :: non_neg_integer(),
                                                           stateless_reset_token :: binary() | undefined,
                                                           max_udp_payload_size :: pos_integer(),
                                                           initial_max_data :: non_neg_integer(),
                                                           initial_max_stream_data_bidi_local ::
                                                               non_neg_integer(),
                                                           initial_max_stream_data_bidi_remote ::
                                                               non_neg_integer(),
                                                           initial_max_stream_data_uni ::
                                                               non_neg_integer(),
                                                           initial_max_streams_bidi :: non_neg_integer(),
                                                           initial_max_streams_uni :: non_neg_integer(),
                                                           ack_delay_exponent :: 0..20,
                                                           max_ack_delay :: non_neg_integer(),
                                                           disable_active_migration :: boolean(),
                                                           preferred_address ::
                                                               nquic_transport:preferred_address() |
                                                               undefined,
                                                           active_connection_id_limit ::
                                                               non_neg_integer(),
                                                           initial_source_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           retry_source_connection_id ::
                                                               nquic:connection_id() | undefined,
                                                           version_information ::
                                                               nquic_transport:version_information() |
                                                               undefined,
                                                           max_datagram_frame_size ::
                                                               non_neg_integer() | undefined} |
                                         undefined,
                                     server_packet_processed :: boolean(),
                                     owner :: pid() | undefined,
                                     owner_mon :: reference() | undefined,
                                     deferred_flush_pending :: boolean(),
                                     pending_ack_count :: non_neg_integer(),
                                     last_idle_ms :: non_neg_integer() | infinity | undefined,
                                     last_pto_ms :: non_neg_integer() | cancel | undefined,
                                     recv_ecn :: nquic_socket:ecn_mark(),
                                     pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                     gso_size :: undefined | pos_integer(),
                                     max_payload_size :: pos_integer(),
                                     server_per_conn_fd :: boolean(),
                                     proactive_cids :: boolean(),
                                     socket_connected :: boolean(),
                                     self_migration_pending :: boolean(),
                                     metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                     spin_enabled :: boolean(),
                                     peer_spin :: 0..1,
                                     new_token_enabled :: boolean(),
                                     new_token_lifetime :: pos_integer(),
                                     qlog :: undefined | nquic_qlog:qlog_state(),
                                     close_kind ::
                                         undefined | local | peer | idle_timeout | protocol_error,
                                     crypto ::
                                         #conn_crypto{tls_state :: term(),
                                                      keys :: #{nquic_packet:space() | rtt0 => map()},
                                                      app_send_keys :: map() | undefined,
                                                      app_recv_keys :: map() | undefined,
                                                      crypto_buffer ::
                                                          #{nquic_packet:space() =>
                                                                {non_neg_integer(), binary(), list()}},
                                                      cipher ::
                                                          aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                                                      cipher_suites ::
                                                          [aes_128_gcm | aes_256_gcm | chacha20_poly1305] |
                                                          undefined,
                                                      key_phase :: boolean(),
                                                      key_update_pending :: boolean(),
                                                      client_app_secret :: binary() | undefined,
                                                      server_app_secret :: binary() | undefined,
                                                      old_read_keys ::
                                                          #{key := binary(), iv := binary()} | undefined,
                                                      zero_rtt_accepted :: boolean(),
                                                      replay_protection :: module() | undefined,
                                                      session_ticket :: map() | undefined,
                                                      resumption_secret :: binary() | undefined,
                                                      session_cache ::
                                                          atom() |
                                                          false |
                                                          {module, module()} |
                                                          undefined,
                                                      token_cache :: atom() | false | {module, module()},
                                                      alpn :: [binary()] | undefined,
                                                      hostname :: string() | binary() | undefined,
                                                      cert :: binary() | undefined,
                                                      cert_chain :: [binary()],
                                                      key :: any() | undefined,
                                                      verify :: verify_none | verify_peer,
                                                      cacerts :: [binary()],
                                                      peer_cert :: binary() | undefined,
                                                      static_key :: binary() | undefined},
                                     streams_state ::
                                         #conn_streams{streams ::
                                                           #{nquic:stream_id() =>
                                                                 #stream_state{stream_id ::
                                                                                   nquic:stream_id(),
                                                                               type :: bidi | uni,
                                                                               send_state ::
                                                                                   ready | send |
                                                                                   data_sent |
                                                                                   data_recvd |
                                                                                   reset_sent |
                                                                                   reset_recvd,
                                                                               send_offset ::
                                                                                   non_neg_integer(),
                                                                               send_max_data ::
                                                                                   non_neg_integer(),
                                                                               last_stream_data_blocked ::
                                                                                   non_neg_integer(),
                                                                               pending_send_data ::
                                                                                   [binary()],
                                                                               pending_send_size ::
                                                                                   non_neg_integer(),
                                                                               pending_send_fin ::
                                                                                   boolean(),
                                                                               recv_state ::
                                                                                   recv | size_known |
                                                                                   data_recvd |
                                                                                   reset_recvd |
                                                                                   data_read |
                                                                                   reset_read,
                                                                               recv_offset ::
                                                                                   non_neg_integer(),
                                                                               recv_max_offset ::
                                                                                   non_neg_integer(),
                                                                               recv_window ::
                                                                                   non_neg_integer(),
                                                                               recv_buffer ::
                                                                                   gb_trees:tree(non_neg_integer(),
                                                                                                 {binary(),
                                                                                                  boolean()}),
                                                                               app_buffer :: iodata(),
                                                                               app_buffer_size ::
                                                                                   non_neg_integer()}},
                                                       next_bidi_stream :: nquic:stream_id() | undefined,
                                                       next_uni_stream :: nquic:stream_id() | undefined,
                                                       peer_max_streams_bidi :: non_neg_integer(),
                                                       peer_max_streams_uni :: non_neg_integer(),
                                                       local_max_streams_bidi :: non_neg_integer(),
                                                       local_max_streams_uni :: non_neg_integer(),
                                                       last_sent_max_streams_bidi :: non_neg_integer(),
                                                       last_sent_max_streams_uni :: non_neg_integer(),
                                                       max_peer_bidi_stream_id ::
                                                           non_neg_integer() | undefined,
                                                       max_peer_uni_stream_id ::
                                                           non_neg_integer() | undefined,
                                                       opened_peer_bidi_count :: non_neg_integer(),
                                                       opened_peer_uni_count :: non_neg_integer(),
                                                       closed_peer_bidi_wm :: integer(),
                                                       closed_peer_uni_wm :: integer(),
                                                       closed_peer_streams ::
                                                           #{nquic:stream_id() => true},
                                                       recv_waiters ::
                                                           #{nquic:stream_id() => gen_statem:from()},
                                                       accept_stream_waiters ::
                                                           queue:queue(gen_statem:from()),
                                                       pending_streams :: queue:queue(nquic:stream_id()),
                                                       blocked_streams :: #{nquic:stream_id() => true},
                                                       pending_send_streams ::
                                                           #{nquic:stream_id() => true},
                                                       send_buffer_high_water :: pos_integer(),
                                                       send_timeout :: timeout(),
                                                       send_waiters ::
                                                           queue:queue(nquic_conn_send_waiters:t())},
                                     flow ::
                                         #conn_flow{local_max_data :: non_neg_integer(),
                                                    remote_max_data :: non_neg_integer(),
                                                    data_sent :: non_neg_integer(),
                                                    data_received :: non_neg_integer(),
                                                    last_data_blocked :: non_neg_integer(),
                                                    pending_initial_frames :: [nquic_frame:t()],
                                                    pending_handshake_frames :: [nquic_frame:t()],
                                                    pending_app_frames :: [nquic_frame:t()],
                                                    pending_app_pre_encoded ::
                                                        [{non_neg_integer(), iodata(), nquic_frame:t()}],
                                                    queued_app_send_bytes :: non_neg_integer()},
                                     path ::
                                         #conn_path_mgmt{path_state :: nquic_path:state() | undefined,
                                                         peer_cids ::
                                                             #{non_neg_integer() =>
                                                                   #{cid := nquic:connection_id(),
                                                                     token := binary()}},
                                                         local_cids ::
                                                             #{non_neg_integer() =>
                                                                   nquic:connection_id()},
                                                         local_cid_seq :: non_neg_integer(),
                                                         peer_retire_prior_to :: non_neg_integer(),
                                                         anti_amp_bytes_received :: non_neg_integer(),
                                                         anti_amp_bytes_sent :: non_neg_integer(),
                                                         address_validated :: boolean()}},
                         bidi | uni) ->
                            #stream_state{stream_id :: nquic:stream_id(),
                                          type :: bidi | uni,
                                          send_state ::
                                              ready | send | data_sent | data_recvd | reset_sent |
                                              reset_recvd,
                                          send_offset :: non_neg_integer(),
                                          send_max_data :: non_neg_integer(),
                                          last_stream_data_blocked :: non_neg_integer(),
                                          pending_send_data :: [binary()],
                                          pending_send_size :: non_neg_integer(),
                                          pending_send_fin :: boolean(),
                                          recv_state ::
                                              recv | size_known | data_recvd | reset_recvd | data_read |
                                              reset_read,
                                          recv_offset :: non_neg_integer(),
                                          recv_max_offset :: non_neg_integer(),
                                          recv_window :: non_neg_integer(),
                                          recv_buffer ::
                                              gb_trees:tree(non_neg_integer(), {binary(), boolean()}),
                                          app_buffer :: iodata(),
                                          app_buffer_size :: non_neg_integer()}.

Initialize stream-level send and receive limits based on stream type and transport parameters.

maybe_update_conn_window(ConnState, WindowSize)

-spec maybe_update_conn_window(#conn_state{role :: client | server,
                                           scid :: nquic:connection_id(),
                                           dcid :: nquic:connection_id(),
                                           odcid :: nquic:connection_id() | undefined,
                                           retry_scid :: nquic:connection_id() | undefined,
                                           retry_token :: binary(),
                                           version :: non_neg_integer(),
                                           version_preference :: [non_neg_integer()],
                                           socket :: nquic_socket:t() | undefined,
                                           peer :: nquic_socket:sockaddr() | undefined,
                                           select_info :: nquic_socket:select_info() | undefined,
                                           pn_spaces :: #{nquic_packet:space() => map()},
                                           app_next_pn :: non_neg_integer(),
                                           app_largest_received :: integer(),
                                           loss_state :: nquic_loss:loss_state() | undefined,
                                           dispatch_table :: nquic_dispatch:t() | undefined,
                                           listener :: pid() | undefined,
                                           connect_waiters :: [gen_server:from()],
                                           local_params ::
                                               #transport_params{original_destination_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 max_idle_timeout :: non_neg_integer(),
                                                                 stateless_reset_token ::
                                                                     binary() | undefined,
                                                                 max_udp_payload_size :: pos_integer(),
                                                                 initial_max_data :: non_neg_integer(),
                                                                 initial_max_stream_data_bidi_local ::
                                                                     non_neg_integer(),
                                                                 initial_max_stream_data_bidi_remote ::
                                                                     non_neg_integer(),
                                                                 initial_max_stream_data_uni ::
                                                                     non_neg_integer(),
                                                                 initial_max_streams_bidi ::
                                                                     non_neg_integer(),
                                                                 initial_max_streams_uni ::
                                                                     non_neg_integer(),
                                                                 ack_delay_exponent :: 0..20,
                                                                 max_ack_delay :: non_neg_integer(),
                                                                 disable_active_migration :: boolean(),
                                                                 preferred_address ::
                                                                     nquic_transport:preferred_address() |
                                                                     undefined,
                                                                 active_connection_id_limit ::
                                                                     non_neg_integer(),
                                                                 initial_source_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 retry_source_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 version_information ::
                                                                     nquic_transport:version_information() |
                                                                     undefined,
                                                                 max_datagram_frame_size ::
                                                                     non_neg_integer() | undefined},
                                           remote_params ::
                                               #transport_params{original_destination_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 max_idle_timeout :: non_neg_integer(),
                                                                 stateless_reset_token ::
                                                                     binary() | undefined,
                                                                 max_udp_payload_size :: pos_integer(),
                                                                 initial_max_data :: non_neg_integer(),
                                                                 initial_max_stream_data_bidi_local ::
                                                                     non_neg_integer(),
                                                                 initial_max_stream_data_bidi_remote ::
                                                                     non_neg_integer(),
                                                                 initial_max_stream_data_uni ::
                                                                     non_neg_integer(),
                                                                 initial_max_streams_bidi ::
                                                                     non_neg_integer(),
                                                                 initial_max_streams_uni ::
                                                                     non_neg_integer(),
                                                                 ack_delay_exponent :: 0..20,
                                                                 max_ack_delay :: non_neg_integer(),
                                                                 disable_active_migration :: boolean(),
                                                                 preferred_address ::
                                                                     nquic_transport:preferred_address() |
                                                                     undefined,
                                                                 active_connection_id_limit ::
                                                                     non_neg_integer(),
                                                                 initial_source_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 retry_source_connection_id ::
                                                                     nquic:connection_id() | undefined,
                                                                 version_information ::
                                                                     nquic_transport:version_information() |
                                                                     undefined,
                                                                 max_datagram_frame_size ::
                                                                     non_neg_integer() | undefined} |
                                               undefined,
                                           server_packet_processed :: boolean(),
                                           owner :: pid() | undefined,
                                           owner_mon :: reference() | undefined,
                                           deferred_flush_pending :: boolean(),
                                           pending_ack_count :: non_neg_integer(),
                                           last_idle_ms :: non_neg_integer() | infinity | undefined,
                                           last_pto_ms :: non_neg_integer() | cancel | undefined,
                                           recv_ecn :: nquic_socket:ecn_mark(),
                                           pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                           gso_size :: undefined | pos_integer(),
                                           max_payload_size :: pos_integer(),
                                           server_per_conn_fd :: boolean(),
                                           proactive_cids :: boolean(),
                                           socket_connected :: boolean(),
                                           self_migration_pending :: boolean(),
                                           metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                           spin_enabled :: boolean(),
                                           peer_spin :: 0..1,
                                           new_token_enabled :: boolean(),
                                           new_token_lifetime :: pos_integer(),
                                           qlog :: undefined | nquic_qlog:qlog_state(),
                                           close_kind ::
                                               undefined | local | peer | idle_timeout | protocol_error,
                                           crypto ::
                                               #conn_crypto{tls_state :: term(),
                                                            keys ::
                                                                #{nquic_packet:space() | rtt0 => map()},
                                                            app_send_keys :: map() | undefined,
                                                            app_recv_keys :: map() | undefined,
                                                            crypto_buffer ::
                                                                #{nquic_packet:space() =>
                                                                      {non_neg_integer(),
                                                                       binary(),
                                                                       list()}},
                                                            cipher ::
                                                                aes_128_gcm | aes_256_gcm |
                                                                chacha20_poly1305,
                                                            cipher_suites ::
                                                                [aes_128_gcm | aes_256_gcm |
                                                                 chacha20_poly1305] |
                                                                undefined,
                                                            key_phase :: boolean(),
                                                            key_update_pending :: boolean(),
                                                            client_app_secret :: binary() | undefined,
                                                            server_app_secret :: binary() | undefined,
                                                            old_read_keys ::
                                                                #{key := binary(), iv := binary()} |
                                                                undefined,
                                                            zero_rtt_accepted :: boolean(),
                                                            replay_protection :: module() | undefined,
                                                            session_ticket :: map() | undefined,
                                                            resumption_secret :: binary() | undefined,
                                                            session_cache ::
                                                                atom() |
                                                                false |
                                                                {module, module()} |
                                                                undefined,
                                                            token_cache ::
                                                                atom() | false | {module, module()},
                                                            alpn :: [binary()] | undefined,
                                                            hostname :: string() | binary() | undefined,
                                                            cert :: binary() | undefined,
                                                            cert_chain :: [binary()],
                                                            key :: any() | undefined,
                                                            verify :: verify_none | verify_peer,
                                                            cacerts :: [binary()],
                                                            peer_cert :: binary() | undefined,
                                                            static_key :: binary() | undefined},
                                           streams_state ::
                                               #conn_streams{streams ::
                                                                 #{nquic:stream_id() =>
                                                                       #stream_state{stream_id ::
                                                                                         nquic:stream_id(),
                                                                                     type :: bidi | uni,
                                                                                     send_state ::
                                                                                         ready | send |
                                                                                         data_sent |
                                                                                         data_recvd |
                                                                                         reset_sent |
                                                                                         reset_recvd,
                                                                                     send_offset ::
                                                                                         non_neg_integer(),
                                                                                     send_max_data ::
                                                                                         non_neg_integer(),
                                                                                     last_stream_data_blocked ::
                                                                                         non_neg_integer(),
                                                                                     pending_send_data ::
                                                                                         [binary()],
                                                                                     pending_send_size ::
                                                                                         non_neg_integer(),
                                                                                     pending_send_fin ::
                                                                                         boolean(),
                                                                                     recv_state ::
                                                                                         recv |
                                                                                         size_known |
                                                                                         data_recvd |
                                                                                         reset_recvd |
                                                                                         data_read |
                                                                                         reset_read,
                                                                                     recv_offset ::
                                                                                         non_neg_integer(),
                                                                                     recv_max_offset ::
                                                                                         non_neg_integer(),
                                                                                     recv_window ::
                                                                                         non_neg_integer(),
                                                                                     recv_buffer ::
                                                                                         gb_trees:tree(non_neg_integer(),
                                                                                                       {binary(),
                                                                                                        boolean()}),
                                                                                     app_buffer ::
                                                                                         iodata(),
                                                                                     app_buffer_size ::
                                                                                         non_neg_integer()}},
                                                             next_bidi_stream ::
                                                                 nquic:stream_id() | undefined,
                                                             next_uni_stream ::
                                                                 nquic:stream_id() | undefined,
                                                             peer_max_streams_bidi :: non_neg_integer(),
                                                             peer_max_streams_uni :: non_neg_integer(),
                                                             local_max_streams_bidi :: non_neg_integer(),
                                                             local_max_streams_uni :: non_neg_integer(),
                                                             last_sent_max_streams_bidi ::
                                                                 non_neg_integer(),
                                                             last_sent_max_streams_uni ::
                                                                 non_neg_integer(),
                                                             max_peer_bidi_stream_id ::
                                                                 non_neg_integer() | undefined,
                                                             max_peer_uni_stream_id ::
                                                                 non_neg_integer() | undefined,
                                                             opened_peer_bidi_count :: non_neg_integer(),
                                                             opened_peer_uni_count :: non_neg_integer(),
                                                             closed_peer_bidi_wm :: integer(),
                                                             closed_peer_uni_wm :: integer(),
                                                             closed_peer_streams ::
                                                                 #{nquic:stream_id() => true},
                                                             recv_waiters ::
                                                                 #{nquic:stream_id() =>
                                                                       gen_statem:from()},
                                                             accept_stream_waiters ::
                                                                 queue:queue(gen_statem:from()),
                                                             pending_streams ::
                                                                 queue:queue(nquic:stream_id()),
                                                             blocked_streams ::
                                                                 #{nquic:stream_id() => true},
                                                             pending_send_streams ::
                                                                 #{nquic:stream_id() => true},
                                                             send_buffer_high_water :: pos_integer(),
                                                             send_timeout :: timeout(),
                                                             send_waiters ::
                                                                 queue:queue(nquic_conn_send_waiters:t())},
                                           flow ::
                                               #conn_flow{local_max_data :: non_neg_integer(),
                                                          remote_max_data :: non_neg_integer(),
                                                          data_sent :: non_neg_integer(),
                                                          data_received :: non_neg_integer(),
                                                          last_data_blocked :: non_neg_integer(),
                                                          pending_initial_frames :: [nquic_frame:t()],
                                                          pending_handshake_frames :: [nquic_frame:t()],
                                                          pending_app_frames :: [nquic_frame:t()],
                                                          pending_app_pre_encoded ::
                                                              [{non_neg_integer(),
                                                                iodata(),
                                                                nquic_frame:t()}],
                                                          queued_app_send_bytes :: non_neg_integer()},
                                           path ::
                                               #conn_path_mgmt{path_state ::
                                                                   nquic_path:state() | undefined,
                                                               peer_cids ::
                                                                   #{non_neg_integer() =>
                                                                         #{cid := nquic:connection_id(),
                                                                           token := binary()}},
                                                               local_cids ::
                                                                   #{non_neg_integer() =>
                                                                         nquic:connection_id()},
                                                               local_cid_seq :: non_neg_integer(),
                                                               peer_retire_prior_to :: non_neg_integer(),
                                                               anti_amp_bytes_received ::
                                                                   non_neg_integer(),
                                                               anti_amp_bytes_sent :: non_neg_integer(),
                                                               address_validated :: boolean()}},
                               pos_integer()) ->
                                  {ok,
                                   #conn_state{role :: client | server,
                                               scid :: nquic:connection_id(),
                                               dcid :: nquic:connection_id(),
                                               odcid :: nquic:connection_id() | undefined,
                                               retry_scid :: nquic:connection_id() | undefined,
                                               retry_token :: binary(),
                                               version :: non_neg_integer(),
                                               version_preference :: [non_neg_integer()],
                                               socket :: nquic_socket:t() | undefined,
                                               peer :: nquic_socket:sockaddr() | undefined,
                                               select_info :: nquic_socket:select_info() | undefined,
                                               pn_spaces :: #{nquic_packet:space() => map()},
                                               app_next_pn :: non_neg_integer(),
                                               app_largest_received :: integer(),
                                               loss_state :: nquic_loss:loss_state() | undefined,
                                               dispatch_table :: nquic_dispatch:t() | undefined,
                                               listener :: pid() | undefined,
                                               connect_waiters :: [gen_server:from()],
                                               local_params ::
                                                   #transport_params{original_destination_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     max_idle_timeout ::
                                                                         non_neg_integer(),
                                                                     stateless_reset_token ::
                                                                         binary() | undefined,
                                                                     max_udp_payload_size ::
                                                                         pos_integer(),
                                                                     initial_max_data ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_bidi_local ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_bidi_remote ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_uni ::
                                                                         non_neg_integer(),
                                                                     initial_max_streams_bidi ::
                                                                         non_neg_integer(),
                                                                     initial_max_streams_uni ::
                                                                         non_neg_integer(),
                                                                     ack_delay_exponent :: 0..20,
                                                                     max_ack_delay :: non_neg_integer(),
                                                                     disable_active_migration ::
                                                                         boolean(),
                                                                     preferred_address ::
                                                                         nquic_transport:preferred_address() |
                                                                         undefined,
                                                                     active_connection_id_limit ::
                                                                         non_neg_integer(),
                                                                     initial_source_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     retry_source_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     version_information ::
                                                                         nquic_transport:version_information() |
                                                                         undefined,
                                                                     max_datagram_frame_size ::
                                                                         non_neg_integer() | undefined},
                                               remote_params ::
                                                   #transport_params{original_destination_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     max_idle_timeout ::
                                                                         non_neg_integer(),
                                                                     stateless_reset_token ::
                                                                         binary() | undefined,
                                                                     max_udp_payload_size ::
                                                                         pos_integer(),
                                                                     initial_max_data ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_bidi_local ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_bidi_remote ::
                                                                         non_neg_integer(),
                                                                     initial_max_stream_data_uni ::
                                                                         non_neg_integer(),
                                                                     initial_max_streams_bidi ::
                                                                         non_neg_integer(),
                                                                     initial_max_streams_uni ::
                                                                         non_neg_integer(),
                                                                     ack_delay_exponent :: 0..20,
                                                                     max_ack_delay :: non_neg_integer(),
                                                                     disable_active_migration ::
                                                                         boolean(),
                                                                     preferred_address ::
                                                                         nquic_transport:preferred_address() |
                                                                         undefined,
                                                                     active_connection_id_limit ::
                                                                         non_neg_integer(),
                                                                     initial_source_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     retry_source_connection_id ::
                                                                         nquic:connection_id() |
                                                                         undefined,
                                                                     version_information ::
                                                                         nquic_transport:version_information() |
                                                                         undefined,
                                                                     max_datagram_frame_size ::
                                                                         non_neg_integer() | undefined} |
                                                   undefined,
                                               server_packet_processed :: boolean(),
                                               owner :: pid() | undefined,
                                               owner_mon :: reference() | undefined,
                                               deferred_flush_pending :: boolean(),
                                               pending_ack_count :: non_neg_integer(),
                                               last_idle_ms :: non_neg_integer() | infinity | undefined,
                                               last_pto_ms :: non_neg_integer() | cancel | undefined,
                                               recv_ecn :: nquic_socket:ecn_mark(),
                                               pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                               gso_size :: undefined | pos_integer(),
                                               max_payload_size :: pos_integer(),
                                               server_per_conn_fd :: boolean(),
                                               proactive_cids :: boolean(),
                                               socket_connected :: boolean(),
                                               self_migration_pending :: boolean(),
                                               metrics_counters ::
                                                   nquic_metrics:conn_counters() | undefined,
                                               spin_enabled :: boolean(),
                                               peer_spin :: 0..1,
                                               new_token_enabled :: boolean(),
                                               new_token_lifetime :: pos_integer(),
                                               qlog :: undefined | nquic_qlog:qlog_state(),
                                               close_kind ::
                                                   undefined | local | peer | idle_timeout |
                                                   protocol_error,
                                               crypto ::
                                                   #conn_crypto{tls_state :: term(),
                                                                keys ::
                                                                    #{nquic_packet:space() | rtt0 =>
                                                                          map()},
                                                                app_send_keys :: map() | undefined,
                                                                app_recv_keys :: map() | undefined,
                                                                crypto_buffer ::
                                                                    #{nquic_packet:space() =>
                                                                          {non_neg_integer(),
                                                                           binary(),
                                                                           list()}},
                                                                cipher ::
                                                                    aes_128_gcm | aes_256_gcm |
                                                                    chacha20_poly1305,
                                                                cipher_suites ::
                                                                    [aes_128_gcm | aes_256_gcm |
                                                                     chacha20_poly1305] |
                                                                    undefined,
                                                                key_phase :: boolean(),
                                                                key_update_pending :: boolean(),
                                                                client_app_secret ::
                                                                    binary() | undefined,
                                                                server_app_secret ::
                                                                    binary() | undefined,
                                                                old_read_keys ::
                                                                    #{key := binary(), iv := binary()} |
                                                                    undefined,
                                                                zero_rtt_accepted :: boolean(),
                                                                replay_protection ::
                                                                    module() | undefined,
                                                                session_ticket :: map() | undefined,
                                                                resumption_secret ::
                                                                    binary() | undefined,
                                                                session_cache ::
                                                                    atom() |
                                                                    false |
                                                                    {module, module()} |
                                                                    undefined,
                                                                token_cache ::
                                                                    atom() | false | {module, module()},
                                                                alpn :: [binary()] | undefined,
                                                                hostname ::
                                                                    string() | binary() | undefined,
                                                                cert :: binary() | undefined,
                                                                cert_chain :: [binary()],
                                                                key :: any() | undefined,
                                                                verify :: verify_none | verify_peer,
                                                                cacerts :: [binary()],
                                                                peer_cert :: binary() | undefined,
                                                                static_key :: binary() | undefined},
                                               streams_state ::
                                                   #conn_streams{streams ::
                                                                     #{nquic:stream_id() =>
                                                                           #stream_state{stream_id ::
                                                                                             nquic:stream_id(),
                                                                                         type ::
                                                                                             bidi | uni,
                                                                                         send_state ::
                                                                                             ready |
                                                                                             send |
                                                                                             data_sent |
                                                                                             data_recvd |
                                                                                             reset_sent |
                                                                                             reset_recvd,
                                                                                         send_offset ::
                                                                                             non_neg_integer(),
                                                                                         send_max_data ::
                                                                                             non_neg_integer(),
                                                                                         last_stream_data_blocked ::
                                                                                             non_neg_integer(),
                                                                                         pending_send_data ::
                                                                                             [binary()],
                                                                                         pending_send_size ::
                                                                                             non_neg_integer(),
                                                                                         pending_send_fin ::
                                                                                             boolean(),
                                                                                         recv_state ::
                                                                                             recv |
                                                                                             size_known |
                                                                                             data_recvd |
                                                                                             reset_recvd |
                                                                                             data_read |
                                                                                             reset_read,
                                                                                         recv_offset ::
                                                                                             non_neg_integer(),
                                                                                         recv_max_offset ::
                                                                                             non_neg_integer(),
                                                                                         recv_window ::
                                                                                             non_neg_integer(),
                                                                                         recv_buffer ::
                                                                                             gb_trees:tree(non_neg_integer(),
                                                                                                           {binary(),
                                                                                                            boolean()}),
                                                                                         app_buffer ::
                                                                                             iodata(),
                                                                                         app_buffer_size ::
                                                                                             non_neg_integer()}},
                                                                 next_bidi_stream ::
                                                                     nquic:stream_id() | undefined,
                                                                 next_uni_stream ::
                                                                     nquic:stream_id() | undefined,
                                                                 peer_max_streams_bidi ::
                                                                     non_neg_integer(),
                                                                 peer_max_streams_uni ::
                                                                     non_neg_integer(),
                                                                 local_max_streams_bidi ::
                                                                     non_neg_integer(),
                                                                 local_max_streams_uni ::
                                                                     non_neg_integer(),
                                                                 last_sent_max_streams_bidi ::
                                                                     non_neg_integer(),
                                                                 last_sent_max_streams_uni ::
                                                                     non_neg_integer(),
                                                                 max_peer_bidi_stream_id ::
                                                                     non_neg_integer() | undefined,
                                                                 max_peer_uni_stream_id ::
                                                                     non_neg_integer() | undefined,
                                                                 opened_peer_bidi_count ::
                                                                     non_neg_integer(),
                                                                 opened_peer_uni_count ::
                                                                     non_neg_integer(),
                                                                 closed_peer_bidi_wm :: integer(),
                                                                 closed_peer_uni_wm :: integer(),
                                                                 closed_peer_streams ::
                                                                     #{nquic:stream_id() => true},
                                                                 recv_waiters ::
                                                                     #{nquic:stream_id() =>
                                                                           gen_statem:from()},
                                                                 accept_stream_waiters ::
                                                                     queue:queue(gen_statem:from()),
                                                                 pending_streams ::
                                                                     queue:queue(nquic:stream_id()),
                                                                 blocked_streams ::
                                                                     #{nquic:stream_id() => true},
                                                                 pending_send_streams ::
                                                                     #{nquic:stream_id() => true},
                                                                 send_buffer_high_water :: pos_integer(),
                                                                 send_timeout :: timeout(),
                                                                 send_waiters ::
                                                                     queue:queue(nquic_conn_send_waiters:t())},
                                               flow ::
                                                   #conn_flow{local_max_data :: non_neg_integer(),
                                                              remote_max_data :: non_neg_integer(),
                                                              data_sent :: non_neg_integer(),
                                                              data_received :: non_neg_integer(),
                                                              last_data_blocked :: non_neg_integer(),
                                                              pending_initial_frames ::
                                                                  [nquic_frame:t()],
                                                              pending_handshake_frames ::
                                                                  [nquic_frame:t()],
                                                              pending_app_frames :: [nquic_frame:t()],
                                                              pending_app_pre_encoded ::
                                                                  [{non_neg_integer(),
                                                                    iodata(),
                                                                    nquic_frame:t()}],
                                                              queued_app_send_bytes :: non_neg_integer()},
                                               path ::
                                                   #conn_path_mgmt{path_state ::
                                                                       nquic_path:state() | undefined,
                                                                   peer_cids ::
                                                                       #{non_neg_integer() =>
                                                                             #{cid :=
                                                                                   nquic:connection_id(),
                                                                               token := binary()}},
                                                                   local_cids ::
                                                                       #{non_neg_integer() =>
                                                                             nquic:connection_id()},
                                                                   local_cid_seq :: non_neg_integer(),
                                                                   peer_retire_prior_to ::
                                                                       non_neg_integer(),
                                                                   anti_amp_bytes_received ::
                                                                       non_neg_integer(),
                                                                   anti_amp_bytes_sent ::
                                                                       non_neg_integer(),
                                                                   address_validated :: boolean()}},
                                   nquic_frame:t()} |
                                  false.

Generate a MAX_DATA frame if the connection receive window is below half the target size.

maybe_update_stream_window(StreamState, WindowSize)

-spec maybe_update_stream_window(#stream_state{stream_id :: nquic:stream_id(),
                                               type :: bidi | uni,
                                               send_state ::
                                                   ready | send | data_sent | data_recvd | reset_sent |
                                                   reset_recvd,
                                               send_offset :: non_neg_integer(),
                                               send_max_data :: non_neg_integer(),
                                               last_stream_data_blocked :: non_neg_integer(),
                                               pending_send_data :: [binary()],
                                               pending_send_size :: non_neg_integer(),
                                               pending_send_fin :: boolean(),
                                               recv_state ::
                                                   recv | size_known | data_recvd | reset_recvd |
                                                   data_read | reset_read,
                                               recv_offset :: non_neg_integer(),
                                               recv_max_offset :: non_neg_integer(),
                                               recv_window :: non_neg_integer(),
                                               recv_buffer ::
                                                   gb_trees:tree(non_neg_integer(),
                                                                 {binary(), boolean()}),
                                               app_buffer :: iodata(),
                                               app_buffer_size :: non_neg_integer()},
                                 pos_integer()) ->
                                    {ok,
                                     #stream_state{stream_id :: nquic:stream_id(),
                                                   type :: bidi | uni,
                                                   send_state ::
                                                       ready | send | data_sent | data_recvd |
                                                       reset_sent | reset_recvd,
                                                   send_offset :: non_neg_integer(),
                                                   send_max_data :: non_neg_integer(),
                                                   last_stream_data_blocked :: non_neg_integer(),
                                                   pending_send_data :: [binary()],
                                                   pending_send_size :: non_neg_integer(),
                                                   pending_send_fin :: boolean(),
                                                   recv_state ::
                                                       recv | size_known | data_recvd | reset_recvd |
                                                       data_read | reset_read,
                                                   recv_offset :: non_neg_integer(),
                                                   recv_max_offset :: non_neg_integer(),
                                                   recv_window :: non_neg_integer(),
                                                   recv_buffer ::
                                                       gb_trees:tree(non_neg_integer(),
                                                                     {binary(), boolean()}),
                                                   app_buffer :: iodata(),
                                                   app_buffer_size :: non_neg_integer()},
                                     nquic_frame:t()} |
                                    false.

Generate a MAX_STREAM_DATA frame if the stream receive window is below half the target size.

on_stream_data_received(ConnState, StreamState, Offset, Length)

-spec on_stream_data_received(#conn_state{role :: client | server,
                                          scid :: nquic:connection_id(),
                                          dcid :: nquic:connection_id(),
                                          odcid :: nquic:connection_id() | undefined,
                                          retry_scid :: nquic:connection_id() | undefined,
                                          retry_token :: binary(),
                                          version :: non_neg_integer(),
                                          version_preference :: [non_neg_integer()],
                                          socket :: nquic_socket:t() | undefined,
                                          peer :: nquic_socket:sockaddr() | undefined,
                                          select_info :: nquic_socket:select_info() | undefined,
                                          pn_spaces :: #{nquic_packet:space() => map()},
                                          app_next_pn :: non_neg_integer(),
                                          app_largest_received :: integer(),
                                          loss_state :: nquic_loss:loss_state() | undefined,
                                          dispatch_table :: nquic_dispatch:t() | undefined,
                                          listener :: pid() | undefined,
                                          connect_waiters :: [gen_server:from()],
                                          local_params ::
                                              #transport_params{original_destination_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                max_idle_timeout :: non_neg_integer(),
                                                                stateless_reset_token ::
                                                                    binary() | undefined,
                                                                max_udp_payload_size :: pos_integer(),
                                                                initial_max_data :: non_neg_integer(),
                                                                initial_max_stream_data_bidi_local ::
                                                                    non_neg_integer(),
                                                                initial_max_stream_data_bidi_remote ::
                                                                    non_neg_integer(),
                                                                initial_max_stream_data_uni ::
                                                                    non_neg_integer(),
                                                                initial_max_streams_bidi ::
                                                                    non_neg_integer(),
                                                                initial_max_streams_uni ::
                                                                    non_neg_integer(),
                                                                ack_delay_exponent :: 0..20,
                                                                max_ack_delay :: non_neg_integer(),
                                                                disable_active_migration :: boolean(),
                                                                preferred_address ::
                                                                    nquic_transport:preferred_address() |
                                                                    undefined,
                                                                active_connection_id_limit ::
                                                                    non_neg_integer(),
                                                                initial_source_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                retry_source_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                version_information ::
                                                                    nquic_transport:version_information() |
                                                                    undefined,
                                                                max_datagram_frame_size ::
                                                                    non_neg_integer() | undefined},
                                          remote_params ::
                                              #transport_params{original_destination_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                max_idle_timeout :: non_neg_integer(),
                                                                stateless_reset_token ::
                                                                    binary() | undefined,
                                                                max_udp_payload_size :: pos_integer(),
                                                                initial_max_data :: non_neg_integer(),
                                                                initial_max_stream_data_bidi_local ::
                                                                    non_neg_integer(),
                                                                initial_max_stream_data_bidi_remote ::
                                                                    non_neg_integer(),
                                                                initial_max_stream_data_uni ::
                                                                    non_neg_integer(),
                                                                initial_max_streams_bidi ::
                                                                    non_neg_integer(),
                                                                initial_max_streams_uni ::
                                                                    non_neg_integer(),
                                                                ack_delay_exponent :: 0..20,
                                                                max_ack_delay :: non_neg_integer(),
                                                                disable_active_migration :: boolean(),
                                                                preferred_address ::
                                                                    nquic_transport:preferred_address() |
                                                                    undefined,
                                                                active_connection_id_limit ::
                                                                    non_neg_integer(),
                                                                initial_source_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                retry_source_connection_id ::
                                                                    nquic:connection_id() | undefined,
                                                                version_information ::
                                                                    nquic_transport:version_information() |
                                                                    undefined,
                                                                max_datagram_frame_size ::
                                                                    non_neg_integer() | undefined} |
                                              undefined,
                                          server_packet_processed :: boolean(),
                                          owner :: pid() | undefined,
                                          owner_mon :: reference() | undefined,
                                          deferred_flush_pending :: boolean(),
                                          pending_ack_count :: non_neg_integer(),
                                          last_idle_ms :: non_neg_integer() | infinity | undefined,
                                          last_pto_ms :: non_neg_integer() | cancel | undefined,
                                          recv_ecn :: nquic_socket:ecn_mark(),
                                          pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                          gso_size :: undefined | pos_integer(),
                                          max_payload_size :: pos_integer(),
                                          server_per_conn_fd :: boolean(),
                                          proactive_cids :: boolean(),
                                          socket_connected :: boolean(),
                                          self_migration_pending :: boolean(),
                                          metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                          spin_enabled :: boolean(),
                                          peer_spin :: 0..1,
                                          new_token_enabled :: boolean(),
                                          new_token_lifetime :: pos_integer(),
                                          qlog :: undefined | nquic_qlog:qlog_state(),
                                          close_kind ::
                                              undefined | local | peer | idle_timeout | protocol_error,
                                          crypto ::
                                              #conn_crypto{tls_state :: term(),
                                                           keys ::
                                                               #{nquic_packet:space() | rtt0 => map()},
                                                           app_send_keys :: map() | undefined,
                                                           app_recv_keys :: map() | undefined,
                                                           crypto_buffer ::
                                                               #{nquic_packet:space() =>
                                                                     {non_neg_integer(),
                                                                      binary(),
                                                                      list()}},
                                                           cipher ::
                                                               aes_128_gcm | aes_256_gcm |
                                                               chacha20_poly1305,
                                                           cipher_suites ::
                                                               [aes_128_gcm | aes_256_gcm |
                                                                chacha20_poly1305] |
                                                               undefined,
                                                           key_phase :: boolean(),
                                                           key_update_pending :: boolean(),
                                                           client_app_secret :: binary() | undefined,
                                                           server_app_secret :: binary() | undefined,
                                                           old_read_keys ::
                                                               #{key := binary(), iv := binary()} |
                                                               undefined,
                                                           zero_rtt_accepted :: boolean(),
                                                           replay_protection :: module() | undefined,
                                                           session_ticket :: map() | undefined,
                                                           resumption_secret :: binary() | undefined,
                                                           session_cache ::
                                                               atom() |
                                                               false |
                                                               {module, module()} |
                                                               undefined,
                                                           token_cache ::
                                                               atom() | false | {module, module()},
                                                           alpn :: [binary()] | undefined,
                                                           hostname :: string() | binary() | undefined,
                                                           cert :: binary() | undefined,
                                                           cert_chain :: [binary()],
                                                           key :: any() | undefined,
                                                           verify :: verify_none | verify_peer,
                                                           cacerts :: [binary()],
                                                           peer_cert :: binary() | undefined,
                                                           static_key :: binary() | undefined},
                                          streams_state ::
                                              #conn_streams{streams ::
                                                                #{nquic:stream_id() =>
                                                                      #stream_state{stream_id ::
                                                                                        nquic:stream_id(),
                                                                                    type :: bidi | uni,
                                                                                    send_state ::
                                                                                        ready | send |
                                                                                        data_sent |
                                                                                        data_recvd |
                                                                                        reset_sent |
                                                                                        reset_recvd,
                                                                                    send_offset ::
                                                                                        non_neg_integer(),
                                                                                    send_max_data ::
                                                                                        non_neg_integer(),
                                                                                    last_stream_data_blocked ::
                                                                                        non_neg_integer(),
                                                                                    pending_send_data ::
                                                                                        [binary()],
                                                                                    pending_send_size ::
                                                                                        non_neg_integer(),
                                                                                    pending_send_fin ::
                                                                                        boolean(),
                                                                                    recv_state ::
                                                                                        recv |
                                                                                        size_known |
                                                                                        data_recvd |
                                                                                        reset_recvd |
                                                                                        data_read |
                                                                                        reset_read,
                                                                                    recv_offset ::
                                                                                        non_neg_integer(),
                                                                                    recv_max_offset ::
                                                                                        non_neg_integer(),
                                                                                    recv_window ::
                                                                                        non_neg_integer(),
                                                                                    recv_buffer ::
                                                                                        gb_trees:tree(non_neg_integer(),
                                                                                                      {binary(),
                                                                                                       boolean()}),
                                                                                    app_buffer ::
                                                                                        iodata(),
                                                                                    app_buffer_size ::
                                                                                        non_neg_integer()}},
                                                            next_bidi_stream ::
                                                                nquic:stream_id() | undefined,
                                                            next_uni_stream ::
                                                                nquic:stream_id() | undefined,
                                                            peer_max_streams_bidi :: non_neg_integer(),
                                                            peer_max_streams_uni :: non_neg_integer(),
                                                            local_max_streams_bidi :: non_neg_integer(),
                                                            local_max_streams_uni :: non_neg_integer(),
                                                            last_sent_max_streams_bidi ::
                                                                non_neg_integer(),
                                                            last_sent_max_streams_uni ::
                                                                non_neg_integer(),
                                                            max_peer_bidi_stream_id ::
                                                                non_neg_integer() | undefined,
                                                            max_peer_uni_stream_id ::
                                                                non_neg_integer() | undefined,
                                                            opened_peer_bidi_count :: non_neg_integer(),
                                                            opened_peer_uni_count :: non_neg_integer(),
                                                            closed_peer_bidi_wm :: integer(),
                                                            closed_peer_uni_wm :: integer(),
                                                            closed_peer_streams ::
                                                                #{nquic:stream_id() => true},
                                                            recv_waiters ::
                                                                #{nquic:stream_id() => gen_statem:from()},
                                                            accept_stream_waiters ::
                                                                queue:queue(gen_statem:from()),
                                                            pending_streams ::
                                                                queue:queue(nquic:stream_id()),
                                                            blocked_streams ::
                                                                #{nquic:stream_id() => true},
                                                            pending_send_streams ::
                                                                #{nquic:stream_id() => true},
                                                            send_buffer_high_water :: pos_integer(),
                                                            send_timeout :: timeout(),
                                                            send_waiters ::
                                                                queue:queue(nquic_conn_send_waiters:t())},
                                          flow ::
                                              #conn_flow{local_max_data :: non_neg_integer(),
                                                         remote_max_data :: non_neg_integer(),
                                                         data_sent :: non_neg_integer(),
                                                         data_received :: non_neg_integer(),
                                                         last_data_blocked :: non_neg_integer(),
                                                         pending_initial_frames :: [nquic_frame:t()],
                                                         pending_handshake_frames :: [nquic_frame:t()],
                                                         pending_app_frames :: [nquic_frame:t()],
                                                         pending_app_pre_encoded ::
                                                             [{non_neg_integer(),
                                                               iodata(),
                                                               nquic_frame:t()}],
                                                         queued_app_send_bytes :: non_neg_integer()},
                                          path ::
                                              #conn_path_mgmt{path_state ::
                                                                  nquic_path:state() | undefined,
                                                              peer_cids ::
                                                                  #{non_neg_integer() =>
                                                                        #{cid := nquic:connection_id(),
                                                                          token := binary()}},
                                                              local_cids ::
                                                                  #{non_neg_integer() =>
                                                                        nquic:connection_id()},
                                                              local_cid_seq :: non_neg_integer(),
                                                              peer_retire_prior_to :: non_neg_integer(),
                                                              anti_amp_bytes_received ::
                                                                  non_neg_integer(),
                                                              anti_amp_bytes_sent :: non_neg_integer(),
                                                              address_validated :: boolean()}},
                              #stream_state{stream_id :: nquic:stream_id(),
                                            type :: bidi | uni,
                                            send_state ::
                                                ready | send | data_sent | data_recvd | reset_sent |
                                                reset_recvd,
                                            send_offset :: non_neg_integer(),
                                            send_max_data :: non_neg_integer(),
                                            last_stream_data_blocked :: non_neg_integer(),
                                            pending_send_data :: [binary()],
                                            pending_send_size :: non_neg_integer(),
                                            pending_send_fin :: boolean(),
                                            recv_state ::
                                                recv | size_known | data_recvd | reset_recvd |
                                                data_read | reset_read,
                                            recv_offset :: non_neg_integer(),
                                            recv_max_offset :: non_neg_integer(),
                                            recv_window :: non_neg_integer(),
                                            recv_buffer ::
                                                gb_trees:tree(non_neg_integer(), {binary(), boolean()}),
                                            app_buffer :: iodata(),
                                            app_buffer_size :: non_neg_integer()},
                              non_neg_integer(),
                              non_neg_integer()) ->
                                 {ok,
                                  #conn_state{role :: client | server,
                                              scid :: nquic:connection_id(),
                                              dcid :: nquic:connection_id(),
                                              odcid :: nquic:connection_id() | undefined,
                                              retry_scid :: nquic:connection_id() | undefined,
                                              retry_token :: binary(),
                                              version :: non_neg_integer(),
                                              version_preference :: [non_neg_integer()],
                                              socket :: nquic_socket:t() | undefined,
                                              peer :: nquic_socket:sockaddr() | undefined,
                                              select_info :: nquic_socket:select_info() | undefined,
                                              pn_spaces :: #{nquic_packet:space() => map()},
                                              app_next_pn :: non_neg_integer(),
                                              app_largest_received :: integer(),
                                              loss_state :: nquic_loss:loss_state() | undefined,
                                              dispatch_table :: nquic_dispatch:t() | undefined,
                                              listener :: pid() | undefined,
                                              connect_waiters :: [gen_server:from()],
                                              local_params ::
                                                  #transport_params{original_destination_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    max_idle_timeout ::
                                                                        non_neg_integer(),
                                                                    stateless_reset_token ::
                                                                        binary() | undefined,
                                                                    max_udp_payload_size ::
                                                                        pos_integer(),
                                                                    initial_max_data ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_bidi_local ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_bidi_remote ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_uni ::
                                                                        non_neg_integer(),
                                                                    initial_max_streams_bidi ::
                                                                        non_neg_integer(),
                                                                    initial_max_streams_uni ::
                                                                        non_neg_integer(),
                                                                    ack_delay_exponent :: 0..20,
                                                                    max_ack_delay :: non_neg_integer(),
                                                                    disable_active_migration ::
                                                                        boolean(),
                                                                    preferred_address ::
                                                                        nquic_transport:preferred_address() |
                                                                        undefined,
                                                                    active_connection_id_limit ::
                                                                        non_neg_integer(),
                                                                    initial_source_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    retry_source_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    version_information ::
                                                                        nquic_transport:version_information() |
                                                                        undefined,
                                                                    max_datagram_frame_size ::
                                                                        non_neg_integer() | undefined},
                                              remote_params ::
                                                  #transport_params{original_destination_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    max_idle_timeout ::
                                                                        non_neg_integer(),
                                                                    stateless_reset_token ::
                                                                        binary() | undefined,
                                                                    max_udp_payload_size ::
                                                                        pos_integer(),
                                                                    initial_max_data ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_bidi_local ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_bidi_remote ::
                                                                        non_neg_integer(),
                                                                    initial_max_stream_data_uni ::
                                                                        non_neg_integer(),
                                                                    initial_max_streams_bidi ::
                                                                        non_neg_integer(),
                                                                    initial_max_streams_uni ::
                                                                        non_neg_integer(),
                                                                    ack_delay_exponent :: 0..20,
                                                                    max_ack_delay :: non_neg_integer(),
                                                                    disable_active_migration ::
                                                                        boolean(),
                                                                    preferred_address ::
                                                                        nquic_transport:preferred_address() |
                                                                        undefined,
                                                                    active_connection_id_limit ::
                                                                        non_neg_integer(),
                                                                    initial_source_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    retry_source_connection_id ::
                                                                        nquic:connection_id() |
                                                                        undefined,
                                                                    version_information ::
                                                                        nquic_transport:version_information() |
                                                                        undefined,
                                                                    max_datagram_frame_size ::
                                                                        non_neg_integer() | undefined} |
                                                  undefined,
                                              server_packet_processed :: boolean(),
                                              owner :: pid() | undefined,
                                              owner_mon :: reference() | undefined,
                                              deferred_flush_pending :: boolean(),
                                              pending_ack_count :: non_neg_integer(),
                                              last_idle_ms :: non_neg_integer() | infinity | undefined,
                                              last_pto_ms :: non_neg_integer() | cancel | undefined,
                                              recv_ecn :: nquic_socket:ecn_mark(),
                                              pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                              gso_size :: undefined | pos_integer(),
                                              max_payload_size :: pos_integer(),
                                              server_per_conn_fd :: boolean(),
                                              proactive_cids :: boolean(),
                                              socket_connected :: boolean(),
                                              self_migration_pending :: boolean(),
                                              metrics_counters ::
                                                  nquic_metrics:conn_counters() | undefined,
                                              spin_enabled :: boolean(),
                                              peer_spin :: 0..1,
                                              new_token_enabled :: boolean(),
                                              new_token_lifetime :: pos_integer(),
                                              qlog :: undefined | nquic_qlog:qlog_state(),
                                              close_kind ::
                                                  undefined | local | peer | idle_timeout |
                                                  protocol_error,
                                              crypto ::
                                                  #conn_crypto{tls_state :: term(),
                                                               keys ::
                                                                   #{nquic_packet:space() | rtt0 =>
                                                                         map()},
                                                               app_send_keys :: map() | undefined,
                                                               app_recv_keys :: map() | undefined,
                                                               crypto_buffer ::
                                                                   #{nquic_packet:space() =>
                                                                         {non_neg_integer(),
                                                                          binary(),
                                                                          list()}},
                                                               cipher ::
                                                                   aes_128_gcm | aes_256_gcm |
                                                                   chacha20_poly1305,
                                                               cipher_suites ::
                                                                   [aes_128_gcm | aes_256_gcm |
                                                                    chacha20_poly1305] |
                                                                   undefined,
                                                               key_phase :: boolean(),
                                                               key_update_pending :: boolean(),
                                                               client_app_secret :: binary() | undefined,
                                                               server_app_secret :: binary() | undefined,
                                                               old_read_keys ::
                                                                   #{key := binary(), iv := binary()} |
                                                                   undefined,
                                                               zero_rtt_accepted :: boolean(),
                                                               replay_protection :: module() | undefined,
                                                               session_ticket :: map() | undefined,
                                                               resumption_secret :: binary() | undefined,
                                                               session_cache ::
                                                                   atom() |
                                                                   false |
                                                                   {module, module()} |
                                                                   undefined,
                                                               token_cache ::
                                                                   atom() | false | {module, module()},
                                                               alpn :: [binary()] | undefined,
                                                               hostname ::
                                                                   string() | binary() | undefined,
                                                               cert :: binary() | undefined,
                                                               cert_chain :: [binary()],
                                                               key :: any() | undefined,
                                                               verify :: verify_none | verify_peer,
                                                               cacerts :: [binary()],
                                                               peer_cert :: binary() | undefined,
                                                               static_key :: binary() | undefined},
                                              streams_state ::
                                                  #conn_streams{streams ::
                                                                    #{nquic:stream_id() =>
                                                                          #stream_state{stream_id ::
                                                                                            nquic:stream_id(),
                                                                                        type ::
                                                                                            bidi | uni,
                                                                                        send_state ::
                                                                                            ready |
                                                                                            send |
                                                                                            data_sent |
                                                                                            data_recvd |
                                                                                            reset_sent |
                                                                                            reset_recvd,
                                                                                        send_offset ::
                                                                                            non_neg_integer(),
                                                                                        send_max_data ::
                                                                                            non_neg_integer(),
                                                                                        last_stream_data_blocked ::
                                                                                            non_neg_integer(),
                                                                                        pending_send_data ::
                                                                                            [binary()],
                                                                                        pending_send_size ::
                                                                                            non_neg_integer(),
                                                                                        pending_send_fin ::
                                                                                            boolean(),
                                                                                        recv_state ::
                                                                                            recv |
                                                                                            size_known |
                                                                                            data_recvd |
                                                                                            reset_recvd |
                                                                                            data_read |
                                                                                            reset_read,
                                                                                        recv_offset ::
                                                                                            non_neg_integer(),
                                                                                        recv_max_offset ::
                                                                                            non_neg_integer(),
                                                                                        recv_window ::
                                                                                            non_neg_integer(),
                                                                                        recv_buffer ::
                                                                                            gb_trees:tree(non_neg_integer(),
                                                                                                          {binary(),
                                                                                                           boolean()}),
                                                                                        app_buffer ::
                                                                                            iodata(),
                                                                                        app_buffer_size ::
                                                                                            non_neg_integer()}},
                                                                next_bidi_stream ::
                                                                    nquic:stream_id() | undefined,
                                                                next_uni_stream ::
                                                                    nquic:stream_id() | undefined,
                                                                peer_max_streams_bidi ::
                                                                    non_neg_integer(),
                                                                peer_max_streams_uni ::
                                                                    non_neg_integer(),
                                                                local_max_streams_bidi ::
                                                                    non_neg_integer(),
                                                                local_max_streams_uni ::
                                                                    non_neg_integer(),
                                                                last_sent_max_streams_bidi ::
                                                                    non_neg_integer(),
                                                                last_sent_max_streams_uni ::
                                                                    non_neg_integer(),
                                                                max_peer_bidi_stream_id ::
                                                                    non_neg_integer() | undefined,
                                                                max_peer_uni_stream_id ::
                                                                    non_neg_integer() | undefined,
                                                                opened_peer_bidi_count ::
                                                                    non_neg_integer(),
                                                                opened_peer_uni_count ::
                                                                    non_neg_integer(),
                                                                closed_peer_bidi_wm :: integer(),
                                                                closed_peer_uni_wm :: integer(),
                                                                closed_peer_streams ::
                                                                    #{nquic:stream_id() => true},
                                                                recv_waiters ::
                                                                    #{nquic:stream_id() =>
                                                                          gen_statem:from()},
                                                                accept_stream_waiters ::
                                                                    queue:queue(gen_statem:from()),
                                                                pending_streams ::
                                                                    queue:queue(nquic:stream_id()),
                                                                blocked_streams ::
                                                                    #{nquic:stream_id() => true},
                                                                pending_send_streams ::
                                                                    #{nquic:stream_id() => true},
                                                                send_buffer_high_water :: pos_integer(),
                                                                send_timeout :: timeout(),
                                                                send_waiters ::
                                                                    queue:queue(nquic_conn_send_waiters:t())},
                                              flow ::
                                                  #conn_flow{local_max_data :: non_neg_integer(),
                                                             remote_max_data :: non_neg_integer(),
                                                             data_sent :: non_neg_integer(),
                                                             data_received :: non_neg_integer(),
                                                             last_data_blocked :: non_neg_integer(),
                                                             pending_initial_frames :: [nquic_frame:t()],
                                                             pending_handshake_frames ::
                                                                 [nquic_frame:t()],
                                                             pending_app_frames :: [nquic_frame:t()],
                                                             pending_app_pre_encoded ::
                                                                 [{non_neg_integer(),
                                                                   iodata(),
                                                                   nquic_frame:t()}],
                                                             queued_app_send_bytes :: non_neg_integer()},
                                              path ::
                                                  #conn_path_mgmt{path_state ::
                                                                      nquic_path:state() | undefined,
                                                                  peer_cids ::
                                                                      #{non_neg_integer() =>
                                                                            #{cid :=
                                                                                  nquic:connection_id(),
                                                                              token := binary()}},
                                                                  local_cids ::
                                                                      #{non_neg_integer() =>
                                                                            nquic:connection_id()},
                                                                  local_cid_seq :: non_neg_integer(),
                                                                  peer_retire_prior_to ::
                                                                      non_neg_integer(),
                                                                  anti_amp_bytes_received ::
                                                                      non_neg_integer(),
                                                                  anti_amp_bytes_sent ::
                                                                      non_neg_integer(),
                                                                  address_validated :: boolean()}},
                                  #stream_state{stream_id :: nquic:stream_id(),
                                                type :: bidi | uni,
                                                send_state ::
                                                    ready | send | data_sent | data_recvd | reset_sent |
                                                    reset_recvd,
                                                send_offset :: non_neg_integer(),
                                                send_max_data :: non_neg_integer(),
                                                last_stream_data_blocked :: non_neg_integer(),
                                                pending_send_data :: [binary()],
                                                pending_send_size :: non_neg_integer(),
                                                pending_send_fin :: boolean(),
                                                recv_state ::
                                                    recv | size_known | data_recvd | reset_recvd |
                                                    data_read | reset_read,
                                                recv_offset :: non_neg_integer(),
                                                recv_max_offset :: non_neg_integer(),
                                                recv_window :: non_neg_integer(),
                                                recv_buffer ::
                                                    gb_trees:tree(non_neg_integer(),
                                                                  {binary(), boolean()}),
                                                app_buffer :: iodata(),
                                                app_buffer_size :: non_neg_integer()}} |
                                 {error, flow_control_error}.

Update receive offsets after receiving data, returning an error if limits are exceeded.

on_stream_data_sent(ConnState, StreamID, Length)

-spec on_stream_data_sent(#conn_state{role :: client | server,
                                      scid :: nquic:connection_id(),
                                      dcid :: nquic:connection_id(),
                                      odcid :: nquic:connection_id() | undefined,
                                      retry_scid :: nquic:connection_id() | undefined,
                                      retry_token :: binary(),
                                      version :: non_neg_integer(),
                                      version_preference :: [non_neg_integer()],
                                      socket :: nquic_socket:t() | undefined,
                                      peer :: nquic_socket:sockaddr() | undefined,
                                      select_info :: nquic_socket:select_info() | undefined,
                                      pn_spaces :: #{nquic_packet:space() => map()},
                                      app_next_pn :: non_neg_integer(),
                                      app_largest_received :: integer(),
                                      loss_state :: nquic_loss:loss_state() | undefined,
                                      dispatch_table :: nquic_dispatch:t() | undefined,
                                      listener :: pid() | undefined,
                                      connect_waiters :: [gen_server:from()],
                                      local_params ::
                                          #transport_params{original_destination_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            max_idle_timeout :: non_neg_integer(),
                                                            stateless_reset_token ::
                                                                binary() | undefined,
                                                            max_udp_payload_size :: pos_integer(),
                                                            initial_max_data :: non_neg_integer(),
                                                            initial_max_stream_data_bidi_local ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_bidi_remote ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_uni ::
                                                                non_neg_integer(),
                                                            initial_max_streams_bidi ::
                                                                non_neg_integer(),
                                                            initial_max_streams_uni :: non_neg_integer(),
                                                            ack_delay_exponent :: 0..20,
                                                            max_ack_delay :: non_neg_integer(),
                                                            disable_active_migration :: boolean(),
                                                            preferred_address ::
                                                                nquic_transport:preferred_address() |
                                                                undefined,
                                                            active_connection_id_limit ::
                                                                non_neg_integer(),
                                                            initial_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            retry_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            version_information ::
                                                                nquic_transport:version_information() |
                                                                undefined,
                                                            max_datagram_frame_size ::
                                                                non_neg_integer() | undefined},
                                      remote_params ::
                                          #transport_params{original_destination_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            max_idle_timeout :: non_neg_integer(),
                                                            stateless_reset_token ::
                                                                binary() | undefined,
                                                            max_udp_payload_size :: pos_integer(),
                                                            initial_max_data :: non_neg_integer(),
                                                            initial_max_stream_data_bidi_local ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_bidi_remote ::
                                                                non_neg_integer(),
                                                            initial_max_stream_data_uni ::
                                                                non_neg_integer(),
                                                            initial_max_streams_bidi ::
                                                                non_neg_integer(),
                                                            initial_max_streams_uni :: non_neg_integer(),
                                                            ack_delay_exponent :: 0..20,
                                                            max_ack_delay :: non_neg_integer(),
                                                            disable_active_migration :: boolean(),
                                                            preferred_address ::
                                                                nquic_transport:preferred_address() |
                                                                undefined,
                                                            active_connection_id_limit ::
                                                                non_neg_integer(),
                                                            initial_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            retry_source_connection_id ::
                                                                nquic:connection_id() | undefined,
                                                            version_information ::
                                                                nquic_transport:version_information() |
                                                                undefined,
                                                            max_datagram_frame_size ::
                                                                non_neg_integer() | undefined} |
                                          undefined,
                                      server_packet_processed :: boolean(),
                                      owner :: pid() | undefined,
                                      owner_mon :: reference() | undefined,
                                      deferred_flush_pending :: boolean(),
                                      pending_ack_count :: non_neg_integer(),
                                      last_idle_ms :: non_neg_integer() | infinity | undefined,
                                      last_pto_ms :: non_neg_integer() | cancel | undefined,
                                      recv_ecn :: nquic_socket:ecn_mark(),
                                      pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                      gso_size :: undefined | pos_integer(),
                                      max_payload_size :: pos_integer(),
                                      server_per_conn_fd :: boolean(),
                                      proactive_cids :: boolean(),
                                      socket_connected :: boolean(),
                                      self_migration_pending :: boolean(),
                                      metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                      spin_enabled :: boolean(),
                                      peer_spin :: 0..1,
                                      new_token_enabled :: boolean(),
                                      new_token_lifetime :: pos_integer(),
                                      qlog :: undefined | nquic_qlog:qlog_state(),
                                      close_kind ::
                                          undefined | local | peer | idle_timeout | protocol_error,
                                      crypto ::
                                          #conn_crypto{tls_state :: term(),
                                                       keys :: #{nquic_packet:space() | rtt0 => map()},
                                                       app_send_keys :: map() | undefined,
                                                       app_recv_keys :: map() | undefined,
                                                       crypto_buffer ::
                                                           #{nquic_packet:space() =>
                                                                 {non_neg_integer(), binary(), list()}},
                                                       cipher ::
                                                           aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                                                       cipher_suites ::
                                                           [aes_128_gcm | aes_256_gcm |
                                                            chacha20_poly1305] |
                                                           undefined,
                                                       key_phase :: boolean(),
                                                       key_update_pending :: boolean(),
                                                       client_app_secret :: binary() | undefined,
                                                       server_app_secret :: binary() | undefined,
                                                       old_read_keys ::
                                                           #{key := binary(), iv := binary()} |
                                                           undefined,
                                                       zero_rtt_accepted :: boolean(),
                                                       replay_protection :: module() | undefined,
                                                       session_ticket :: map() | undefined,
                                                       resumption_secret :: binary() | undefined,
                                                       session_cache ::
                                                           atom() |
                                                           false |
                                                           {module, module()} |
                                                           undefined,
                                                       token_cache ::
                                                           atom() | false | {module, module()},
                                                       alpn :: [binary()] | undefined,
                                                       hostname :: string() | binary() | undefined,
                                                       cert :: binary() | undefined,
                                                       cert_chain :: [binary()],
                                                       key :: any() | undefined,
                                                       verify :: verify_none | verify_peer,
                                                       cacerts :: [binary()],
                                                       peer_cert :: binary() | undefined,
                                                       static_key :: binary() | undefined},
                                      streams_state ::
                                          #conn_streams{streams ::
                                                            #{nquic:stream_id() =>
                                                                  #stream_state{stream_id ::
                                                                                    nquic:stream_id(),
                                                                                type :: bidi | uni,
                                                                                send_state ::
                                                                                    ready | send |
                                                                                    data_sent |
                                                                                    data_recvd |
                                                                                    reset_sent |
                                                                                    reset_recvd,
                                                                                send_offset ::
                                                                                    non_neg_integer(),
                                                                                send_max_data ::
                                                                                    non_neg_integer(),
                                                                                last_stream_data_blocked ::
                                                                                    non_neg_integer(),
                                                                                pending_send_data ::
                                                                                    [binary()],
                                                                                pending_send_size ::
                                                                                    non_neg_integer(),
                                                                                pending_send_fin ::
                                                                                    boolean(),
                                                                                recv_state ::
                                                                                    recv | size_known |
                                                                                    data_recvd |
                                                                                    reset_recvd |
                                                                                    data_read |
                                                                                    reset_read,
                                                                                recv_offset ::
                                                                                    non_neg_integer(),
                                                                                recv_max_offset ::
                                                                                    non_neg_integer(),
                                                                                recv_window ::
                                                                                    non_neg_integer(),
                                                                                recv_buffer ::
                                                                                    gb_trees:tree(non_neg_integer(),
                                                                                                  {binary(),
                                                                                                   boolean()}),
                                                                                app_buffer :: iodata(),
                                                                                app_buffer_size ::
                                                                                    non_neg_integer()}},
                                                        next_bidi_stream ::
                                                            nquic:stream_id() | undefined,
                                                        next_uni_stream :: nquic:stream_id() | undefined,
                                                        peer_max_streams_bidi :: non_neg_integer(),
                                                        peer_max_streams_uni :: non_neg_integer(),
                                                        local_max_streams_bidi :: non_neg_integer(),
                                                        local_max_streams_uni :: non_neg_integer(),
                                                        last_sent_max_streams_bidi :: non_neg_integer(),
                                                        last_sent_max_streams_uni :: non_neg_integer(),
                                                        max_peer_bidi_stream_id ::
                                                            non_neg_integer() | undefined,
                                                        max_peer_uni_stream_id ::
                                                            non_neg_integer() | undefined,
                                                        opened_peer_bidi_count :: non_neg_integer(),
                                                        opened_peer_uni_count :: non_neg_integer(),
                                                        closed_peer_bidi_wm :: integer(),
                                                        closed_peer_uni_wm :: integer(),
                                                        closed_peer_streams ::
                                                            #{nquic:stream_id() => true},
                                                        recv_waiters ::
                                                            #{nquic:stream_id() => gen_statem:from()},
                                                        accept_stream_waiters ::
                                                            queue:queue(gen_statem:from()),
                                                        pending_streams ::
                                                            queue:queue(nquic:stream_id()),
                                                        blocked_streams :: #{nquic:stream_id() => true},
                                                        pending_send_streams ::
                                                            #{nquic:stream_id() => true},
                                                        send_buffer_high_water :: pos_integer(),
                                                        send_timeout :: timeout(),
                                                        send_waiters ::
                                                            queue:queue(nquic_conn_send_waiters:t())},
                                      flow ::
                                          #conn_flow{local_max_data :: non_neg_integer(),
                                                     remote_max_data :: non_neg_integer(),
                                                     data_sent :: non_neg_integer(),
                                                     data_received :: non_neg_integer(),
                                                     last_data_blocked :: non_neg_integer(),
                                                     pending_initial_frames :: [nquic_frame:t()],
                                                     pending_handshake_frames :: [nquic_frame:t()],
                                                     pending_app_frames :: [nquic_frame:t()],
                                                     pending_app_pre_encoded ::
                                                         [{non_neg_integer(), iodata(), nquic_frame:t()}],
                                                     queued_app_send_bytes :: non_neg_integer()},
                                      path ::
                                          #conn_path_mgmt{path_state :: nquic_path:state() | undefined,
                                                          peer_cids ::
                                                              #{non_neg_integer() =>
                                                                    #{cid := nquic:connection_id(),
                                                                      token := binary()}},
                                                          local_cids ::
                                                              #{non_neg_integer() =>
                                                                    nquic:connection_id()},
                                                          local_cid_seq :: non_neg_integer(),
                                                          peer_retire_prior_to :: non_neg_integer(),
                                                          anti_amp_bytes_received :: non_neg_integer(),
                                                          anti_amp_bytes_sent :: non_neg_integer(),
                                                          address_validated :: boolean()}},
                          nquic:stream_id(),
                          non_neg_integer()) ->
                             #conn_state{role :: client | server,
                                         scid :: nquic:connection_id(),
                                         dcid :: nquic:connection_id(),
                                         odcid :: nquic:connection_id() | undefined,
                                         retry_scid :: nquic:connection_id() | undefined,
                                         retry_token :: binary(),
                                         version :: non_neg_integer(),
                                         version_preference :: [non_neg_integer()],
                                         socket :: nquic_socket:t() | undefined,
                                         peer :: nquic_socket:sockaddr() | undefined,
                                         select_info :: nquic_socket:select_info() | undefined,
                                         pn_spaces :: #{nquic_packet:space() => map()},
                                         app_next_pn :: non_neg_integer(),
                                         app_largest_received :: integer(),
                                         loss_state :: nquic_loss:loss_state() | undefined,
                                         dispatch_table :: nquic_dispatch:t() | undefined,
                                         listener :: pid() | undefined,
                                         connect_waiters :: [gen_server:from()],
                                         local_params ::
                                             #transport_params{original_destination_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               max_idle_timeout :: non_neg_integer(),
                                                               stateless_reset_token ::
                                                                   binary() | undefined,
                                                               max_udp_payload_size :: pos_integer(),
                                                               initial_max_data :: non_neg_integer(),
                                                               initial_max_stream_data_bidi_local ::
                                                                   non_neg_integer(),
                                                               initial_max_stream_data_bidi_remote ::
                                                                   non_neg_integer(),
                                                               initial_max_stream_data_uni ::
                                                                   non_neg_integer(),
                                                               initial_max_streams_bidi ::
                                                                   non_neg_integer(),
                                                               initial_max_streams_uni ::
                                                                   non_neg_integer(),
                                                               ack_delay_exponent :: 0..20,
                                                               max_ack_delay :: non_neg_integer(),
                                                               disable_active_migration :: boolean(),
                                                               preferred_address ::
                                                                   nquic_transport:preferred_address() |
                                                                   undefined,
                                                               active_connection_id_limit ::
                                                                   non_neg_integer(),
                                                               initial_source_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               retry_source_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               version_information ::
                                                                   nquic_transport:version_information() |
                                                                   undefined,
                                                               max_datagram_frame_size ::
                                                                   non_neg_integer() | undefined},
                                         remote_params ::
                                             #transport_params{original_destination_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               max_idle_timeout :: non_neg_integer(),
                                                               stateless_reset_token ::
                                                                   binary() | undefined,
                                                               max_udp_payload_size :: pos_integer(),
                                                               initial_max_data :: non_neg_integer(),
                                                               initial_max_stream_data_bidi_local ::
                                                                   non_neg_integer(),
                                                               initial_max_stream_data_bidi_remote ::
                                                                   non_neg_integer(),
                                                               initial_max_stream_data_uni ::
                                                                   non_neg_integer(),
                                                               initial_max_streams_bidi ::
                                                                   non_neg_integer(),
                                                               initial_max_streams_uni ::
                                                                   non_neg_integer(),
                                                               ack_delay_exponent :: 0..20,
                                                               max_ack_delay :: non_neg_integer(),
                                                               disable_active_migration :: boolean(),
                                                               preferred_address ::
                                                                   nquic_transport:preferred_address() |
                                                                   undefined,
                                                               active_connection_id_limit ::
                                                                   non_neg_integer(),
                                                               initial_source_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               retry_source_connection_id ::
                                                                   nquic:connection_id() | undefined,
                                                               version_information ::
                                                                   nquic_transport:version_information() |
                                                                   undefined,
                                                               max_datagram_frame_size ::
                                                                   non_neg_integer() | undefined} |
                                             undefined,
                                         server_packet_processed :: boolean(),
                                         owner :: pid() | undefined,
                                         owner_mon :: reference() | undefined,
                                         deferred_flush_pending :: boolean(),
                                         pending_ack_count :: non_neg_integer(),
                                         last_idle_ms :: non_neg_integer() | infinity | undefined,
                                         last_pto_ms :: non_neg_integer() | cancel | undefined,
                                         recv_ecn :: nquic_socket:ecn_mark(),
                                         pmtud :: nquic_pmtud:pmtud_state() | undefined,
                                         gso_size :: undefined | pos_integer(),
                                         max_payload_size :: pos_integer(),
                                         server_per_conn_fd :: boolean(),
                                         proactive_cids :: boolean(),
                                         socket_connected :: boolean(),
                                         self_migration_pending :: boolean(),
                                         metrics_counters :: nquic_metrics:conn_counters() | undefined,
                                         spin_enabled :: boolean(),
                                         peer_spin :: 0..1,
                                         new_token_enabled :: boolean(),
                                         new_token_lifetime :: pos_integer(),
                                         qlog :: undefined | nquic_qlog:qlog_state(),
                                         close_kind ::
                                             undefined | local | peer | idle_timeout | protocol_error,
                                         crypto ::
                                             #conn_crypto{tls_state :: term(),
                                                          keys ::
                                                              #{nquic_packet:space() | rtt0 => map()},
                                                          app_send_keys :: map() | undefined,
                                                          app_recv_keys :: map() | undefined,
                                                          crypto_buffer ::
                                                              #{nquic_packet:space() =>
                                                                    {non_neg_integer(),
                                                                     binary(),
                                                                     list()}},
                                                          cipher ::
                                                              aes_128_gcm | aes_256_gcm |
                                                              chacha20_poly1305,
                                                          cipher_suites ::
                                                              [aes_128_gcm | aes_256_gcm |
                                                               chacha20_poly1305] |
                                                              undefined,
                                                          key_phase :: boolean(),
                                                          key_update_pending :: boolean(),
                                                          client_app_secret :: binary() | undefined,
                                                          server_app_secret :: binary() | undefined,
                                                          old_read_keys ::
                                                              #{key := binary(), iv := binary()} |
                                                              undefined,
                                                          zero_rtt_accepted :: boolean(),
                                                          replay_protection :: module() | undefined,
                                                          session_ticket :: map() | undefined,
                                                          resumption_secret :: binary() | undefined,
                                                          session_cache ::
                                                              atom() |
                                                              false |
                                                              {module, module()} |
                                                              undefined,
                                                          token_cache ::
                                                              atom() | false | {module, module()},
                                                          alpn :: [binary()] | undefined,
                                                          hostname :: string() | binary() | undefined,
                                                          cert :: binary() | undefined,
                                                          cert_chain :: [binary()],
                                                          key :: any() | undefined,
                                                          verify :: verify_none | verify_peer,
                                                          cacerts :: [binary()],
                                                          peer_cert :: binary() | undefined,
                                                          static_key :: binary() | undefined},
                                         streams_state ::
                                             #conn_streams{streams ::
                                                               #{nquic:stream_id() =>
                                                                     #stream_state{stream_id ::
                                                                                       nquic:stream_id(),
                                                                                   type :: bidi | uni,
                                                                                   send_state ::
                                                                                       ready | send |
                                                                                       data_sent |
                                                                                       data_recvd |
                                                                                       reset_sent |
                                                                                       reset_recvd,
                                                                                   send_offset ::
                                                                                       non_neg_integer(),
                                                                                   send_max_data ::
                                                                                       non_neg_integer(),
                                                                                   last_stream_data_blocked ::
                                                                                       non_neg_integer(),
                                                                                   pending_send_data ::
                                                                                       [binary()],
                                                                                   pending_send_size ::
                                                                                       non_neg_integer(),
                                                                                   pending_send_fin ::
                                                                                       boolean(),
                                                                                   recv_state ::
                                                                                       recv |
                                                                                       size_known |
                                                                                       data_recvd |
                                                                                       reset_recvd |
                                                                                       data_read |
                                                                                       reset_read,
                                                                                   recv_offset ::
                                                                                       non_neg_integer(),
                                                                                   recv_max_offset ::
                                                                                       non_neg_integer(),
                                                                                   recv_window ::
                                                                                       non_neg_integer(),
                                                                                   recv_buffer ::
                                                                                       gb_trees:tree(non_neg_integer(),
                                                                                                     {binary(),
                                                                                                      boolean()}),
                                                                                   app_buffer ::
                                                                                       iodata(),
                                                                                   app_buffer_size ::
                                                                                       non_neg_integer()}},
                                                           next_bidi_stream ::
                                                               nquic:stream_id() | undefined,
                                                           next_uni_stream ::
                                                               nquic:stream_id() | undefined,
                                                           peer_max_streams_bidi :: non_neg_integer(),
                                                           peer_max_streams_uni :: non_neg_integer(),
                                                           local_max_streams_bidi :: non_neg_integer(),
                                                           local_max_streams_uni :: non_neg_integer(),
                                                           last_sent_max_streams_bidi ::
                                                               non_neg_integer(),
                                                           last_sent_max_streams_uni ::
                                                               non_neg_integer(),
                                                           max_peer_bidi_stream_id ::
                                                               non_neg_integer() | undefined,
                                                           max_peer_uni_stream_id ::
                                                               non_neg_integer() | undefined,
                                                           opened_peer_bidi_count :: non_neg_integer(),
                                                           opened_peer_uni_count :: non_neg_integer(),
                                                           closed_peer_bidi_wm :: integer(),
                                                           closed_peer_uni_wm :: integer(),
                                                           closed_peer_streams ::
                                                               #{nquic:stream_id() => true},
                                                           recv_waiters ::
                                                               #{nquic:stream_id() => gen_statem:from()},
                                                           accept_stream_waiters ::
                                                               queue:queue(gen_statem:from()),
                                                           pending_streams ::
                                                               queue:queue(nquic:stream_id()),
                                                           blocked_streams ::
                                                               #{nquic:stream_id() => true},
                                                           pending_send_streams ::
                                                               #{nquic:stream_id() => true},
                                                           send_buffer_high_water :: pos_integer(),
                                                           send_timeout :: timeout(),
                                                           send_waiters ::
                                                               queue:queue(nquic_conn_send_waiters:t())},
                                         flow ::
                                             #conn_flow{local_max_data :: non_neg_integer(),
                                                        remote_max_data :: non_neg_integer(),
                                                        data_sent :: non_neg_integer(),
                                                        data_received :: non_neg_integer(),
                                                        last_data_blocked :: non_neg_integer(),
                                                        pending_initial_frames :: [nquic_frame:t()],
                                                        pending_handshake_frames :: [nquic_frame:t()],
                                                        pending_app_frames :: [nquic_frame:t()],
                                                        pending_app_pre_encoded ::
                                                            [{non_neg_integer(),
                                                              iodata(),
                                                              nquic_frame:t()}],
                                                        queued_app_send_bytes :: non_neg_integer()},
                                         path ::
                                             #conn_path_mgmt{path_state ::
                                                                 nquic_path:state() | undefined,
                                                             peer_cids ::
                                                                 #{non_neg_integer() =>
                                                                       #{cid := nquic:connection_id(),
                                                                         token := binary()}},
                                                             local_cids ::
                                                                 #{non_neg_integer() =>
                                                                       nquic:connection_id()},
                                                             local_cid_seq :: non_neg_integer(),
                                                             peer_retire_prior_to :: non_neg_integer(),
                                                             anti_amp_bytes_received ::
                                                                 non_neg_integer(),
                                                             anti_amp_bytes_sent :: non_neg_integer(),
                                                             address_validated :: boolean()}}.

Update connection and stream send offsets after sending data on a stream.