LCOV - code coverage report
Current view: top level - waltz/h2 - fd_h2_stream.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 29 85 34.1 %
Date: 2025-08-05 05:04:49 Functions: 4 81 4.9 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_h2_fd_h2_stream_h
       2             : #define HEADER_fd_src_waltz_h2_fd_h2_stream_h
       3             : 
       4             : /* fd_h2_stream.h provides the HTTP/2 stream state machine. */
       5             : 
       6             : #include "fd_h2_base.h"
       7             : #include "fd_h2_proto.h"
       8             : #include "fd_h2_conn.h"
       9             : 
      10             : /* The fd_h2_stream_t object holds the stream state machine.  */
      11             : 
      12             : struct fd_h2_stream {
      13             :   uint stream_id;
      14             :   uint tx_wnd; /* transmit quota available */
      15             :   uint rx_wnd; /* receive window bytes remaining */
      16             : 
      17             :   uchar state;
      18             :   uchar hdrs_seq;
      19             : };
      20             : 
      21           0 : #define FD_H2_STREAM_STATE_IDLE       0
      22         138 : #define FD_H2_STREAM_STATE_OPEN       1
      23           9 : #define FD_H2_STREAM_STATE_CLOSING_TX 2 /* half-closed (local) */
      24           0 : #define FD_H2_STREAM_STATE_CLOSING_RX 3 /* half-closed (remote) */
      25           6 : #define FD_H2_STREAM_STATE_CLOSED     4
      26           0 : #define FD_H2_STREAM_STATE_ILLEGAL    5
      27             : 
      28             : FD_PROTOTYPES_BEGIN
      29             : 
      30             : /* fd_h2_stream_init initializes a stream object.  On return, the stream
      31             :    is in 'IDLE' state and does not have an assigned stream ID. */
      32             : 
      33             : static inline fd_h2_stream_t *
      34         129 : fd_h2_stream_init( fd_h2_stream_t * stream ) {
      35         129 :   *stream = (fd_h2_stream_t){0};
      36         129 :   return stream;
      37         129 : }
      38             : 
      39             : /* fd_h2_stream_open transitions a stream from 'IDLE' to 'OPEN'.
      40             :    In fd_h2, this happens when the local or peer side sends a HEADERS
      41             :    frame.  The TX side of the stream assumes the peer's default send
      42             :    window. */
      43             : 
      44             : static inline fd_h2_stream_t *
      45             : fd_h2_stream_open( fd_h2_stream_t * stream,
      46             :                    fd_h2_conn_t *   conn,
      47         129 :                    uint             stream_id ) {
      48         129 :   *stream = (fd_h2_stream_t) {
      49         129 :     .stream_id = stream_id,
      50         129 :     .state     = FD_H2_STREAM_STATE_OPEN,
      51         129 :     .tx_wnd    = conn->peer_settings.initial_window_size,
      52         129 :     .rx_wnd    = conn->self_settings.initial_window_size,
      53         129 :     .hdrs_seq  = 0U
      54         129 :   };
      55         129 :   conn->stream_active_cnt[ (stream_id&1) ^ (conn->rx_stream_id&1) ]++;
      56         129 :   return stream;
      57         129 : }
      58             : 
      59             : static inline void
      60             : fd_h2_stream_error( fd_h2_stream_t * stream,
      61             :                     fd_h2_rbuf_t *   rbuf_tx,
      62           6 :                     uint             h2_err ) {
      63           6 :   fd_h2_tx_rst_stream( rbuf_tx, stream->stream_id, h2_err );
      64           6 :   stream->state = FD_H2_STREAM_STATE_CLOSED;
      65           6 : }
      66             : 
      67             : /* fd_h2_rst_stream generates a RST_STREAM frame on the given stream.
      68             :    On return, the stream is in CLOSED state, and the underlying stream
      69             :    object and map entry can be discarded.  conn->active_stream_cnt is
      70             :    decremented accordingly. */
      71             : 
      72             : void
      73             : fd_h2_rst_stream( fd_h2_conn_t *   conn,
      74             :                   fd_h2_rbuf_t *   rbuf_tx,
      75             :                   fd_h2_stream_t * stream );
      76             : 
      77             : static inline void
      78             : fd_h2_stream_private_deactivate( fd_h2_stream_t * stream,
      79           0 :                                  fd_h2_conn_t *   conn ) {
      80           0 :   conn->stream_active_cnt[ (stream->stream_id&1) ^ (conn->rx_stream_id&1) ]--;
      81           0 : }
      82             : 
      83             : static inline void
      84             : fd_h2_stream_close_rx( fd_h2_stream_t * stream,
      85           0 :                        fd_h2_conn_t *   conn ) {
      86           0 :   switch( stream->state ) {
      87           0 :   case FD_H2_STREAM_STATE_OPEN:
      88           0 :     stream->state = FD_H2_STREAM_STATE_CLOSING_RX;
      89           0 :     break;
      90           0 :   case FD_H2_STREAM_STATE_CLOSING_TX:
      91           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
      92           0 :     fd_h2_stream_private_deactivate( stream, conn );
      93           0 :     break;
      94           0 :   default:
      95           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
      96           0 :     break;
      97           0 :   }
      98           0 : }
      99             : 
     100             : static inline void
     101             : fd_h2_stream_close_tx( fd_h2_stream_t * stream,
     102           9 :                        fd_h2_conn_t *   conn ) {
     103           9 :   switch( stream->state ) {
     104           9 :   case FD_H2_STREAM_STATE_OPEN:
     105           9 :     stream->state = FD_H2_STREAM_STATE_CLOSING_TX;
     106           9 :     break;
     107           0 :   case FD_H2_STREAM_STATE_CLOSING_RX:
     108           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
     109           0 :     fd_h2_stream_private_deactivate( stream, conn );
     110           0 :     break;
     111           0 :   default:
     112           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
     113           0 :     break;
     114           9 :   }
     115           9 : }
     116             : 
     117             : static inline void
     118             : fd_h2_stream_reset( fd_h2_stream_t * stream,
     119           0 :                     fd_h2_conn_t *   conn ) {
     120           0 :   switch( stream->state ) {
     121           0 :   case FD_H2_STREAM_STATE_OPEN:
     122           0 :   case FD_H2_STREAM_STATE_CLOSING_TX:
     123           0 :   case FD_H2_STREAM_STATE_CLOSING_RX:
     124           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
     125           0 :     fd_h2_stream_private_deactivate( stream, conn );
     126           0 :     break;
     127           0 :   default:
     128           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
     129           0 :     break;
     130           0 :   }
     131           0 : }
     132             : 
     133             : static inline void
     134             : fd_h2_stream_rx_headers( fd_h2_stream_t * stream,
     135             :                          fd_h2_conn_t *   conn,
     136           0 :                          ulong            flags ) {
     137           0 :   if( stream->state == FD_H2_STREAM_STATE_IDLE ) {
     138             :     /* FIXME This is probably redundant */
     139           0 :     stream->state = FD_H2_STREAM_STATE_OPEN;
     140           0 :   }
     141           0 :   if( flags & FD_H2_FLAG_END_STREAM ) {
     142           0 :     fd_h2_stream_close_rx( stream, conn );
     143           0 :   }
     144           0 :   if( flags & FD_H2_FLAG_END_HEADERS ) {
     145           0 :     stream->hdrs_seq = (uchar)( stream->hdrs_seq + 1 );
     146           0 :   }
     147           0 : }
     148             : 
     149             : static inline void
     150             : fd_h2_stream_rx_data( fd_h2_stream_t * stream,
     151             :                       fd_h2_conn_t *   conn,
     152           0 :                       ulong            flags ) {
     153           0 :   if( flags & FD_H2_FLAG_END_STREAM ) {
     154           0 :     fd_h2_stream_close_rx( stream, conn );
     155           0 :   }
     156           0 : }
     157             : 
     158             : FD_PROTOTYPES_END
     159             : 
     160             : #endif /* HEADER_fd_src_waltz_h2_fd_h2_stream_h */

Generated by: LCOV version 1.14