LCOV - code coverage report
Current view: top level - waltz/h2 - fd_h2_stream.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 20 84 23.8 %
Date: 2025-07-01 05:00:49 Functions: 3 72 4.2 %

          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          36 : #define FD_H2_STREAM_STATE_OPEN       1
      23           0 : #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           3 : #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          36 : fd_h2_stream_init( fd_h2_stream_t * stream ) {
      35          36 :   *stream = (fd_h2_stream_t){0};
      36          36 :   return stream;
      37          36 : }
      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 const * conn,
      47          36 :                    uint                 stream_id ) {
      48          36 :   *stream = (fd_h2_stream_t) {
      49          36 :     .stream_id = stream_id,
      50          36 :     .state     = FD_H2_STREAM_STATE_OPEN,
      51          36 :     .tx_wnd    = conn->peer_settings.initial_window_size,
      52          36 :     .rx_wnd    = conn->self_settings.initial_window_size,
      53          36 :     .hdrs_seq  = 0U
      54          36 :   };
      55          36 :   return stream;
      56          36 : }
      57             : 
      58             : static inline void
      59             : fd_h2_stream_error( fd_h2_stream_t * stream,
      60             :                     fd_h2_rbuf_t *   rbuf_tx,
      61           3 :                     uint             h2_err ) {
      62           3 :   fd_h2_tx_rst_stream( rbuf_tx, stream->stream_id, h2_err );
      63           3 :   stream->state = FD_H2_STREAM_STATE_CLOSED;
      64           3 : }
      65             : 
      66             : /* fd_h2_rst_stream generates a RST_STREAM frame on the given stream.
      67             :    On return, the stream is in CLOSED state, and the underlying stream
      68             :    object and map entry can be discarded.  conn->active_stream_cnt is
      69             :    decremented accordingly. */
      70             : 
      71             : void
      72             : fd_h2_rst_stream( fd_h2_conn_t *   conn,
      73             :                   fd_h2_rbuf_t *   rbuf_tx,
      74             :                   fd_h2_stream_t * stream );
      75             : 
      76             : static inline void
      77             : fd_h2_stream_private_deactivate( fd_h2_stream_t * stream,
      78           0 :                                  fd_h2_conn_t *   conn ) {
      79           0 :   conn->stream_active_cnt[ (stream->stream_id&1) ^ (conn->rx_stream_id&1) ]--;
      80           0 : }
      81             : 
      82             : static inline void
      83             : fd_h2_stream_close_rx( fd_h2_stream_t * stream,
      84           0 :                        fd_h2_conn_t *   conn ) {
      85           0 :   switch( stream->state ) {
      86           0 :   case FD_H2_STREAM_STATE_OPEN:
      87           0 :     stream->state = FD_H2_STREAM_STATE_CLOSING_RX;
      88           0 :     break;
      89           0 :   case FD_H2_STREAM_STATE_CLOSING_TX:
      90           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
      91           0 :     fd_h2_stream_private_deactivate( stream, conn );
      92           0 :     break;
      93           0 :   default:
      94           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
      95           0 :     break;
      96           0 :   }
      97           0 : }
      98             : 
      99             : static inline void
     100             : fd_h2_stream_close_tx( fd_h2_stream_t * stream,
     101           0 :                        fd_h2_conn_t *   conn ) {
     102           0 :   switch( stream->state ) {
     103           0 :   case FD_H2_STREAM_STATE_OPEN:
     104           0 :     stream->state = FD_H2_STREAM_STATE_CLOSING_TX;
     105           0 :     break;
     106           0 :   case FD_H2_STREAM_STATE_CLOSING_RX:
     107           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
     108           0 :     fd_h2_stream_private_deactivate( stream, conn );
     109           0 :     break;
     110           0 :   default:
     111           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
     112           0 :     break;
     113           0 :   }
     114           0 : }
     115             : 
     116             : static inline void
     117             : fd_h2_stream_reset( fd_h2_stream_t * stream,
     118           0 :                     fd_h2_conn_t *   conn ) {
     119           0 :   switch( stream->state ) {
     120           0 :   case FD_H2_STREAM_STATE_OPEN:
     121           0 :   case FD_H2_STREAM_STATE_CLOSING_TX:
     122           0 :   case FD_H2_STREAM_STATE_CLOSING_RX:
     123           0 :     stream->state = FD_H2_STREAM_STATE_CLOSED;
     124           0 :     fd_h2_stream_private_deactivate( stream, conn );
     125           0 :     break;
     126           0 :   default:
     127           0 :     stream->state = FD_H2_STREAM_STATE_ILLEGAL;
     128           0 :     break;
     129           0 :   }
     130           0 : }
     131             : 
     132             : static inline void
     133             : fd_h2_stream_rx_headers( fd_h2_stream_t * stream,
     134             :                          fd_h2_conn_t *   conn,
     135           0 :                          ulong            flags ) {
     136           0 :   if( stream->state == FD_H2_STREAM_STATE_IDLE ) {
     137             :     /* FIXME This is probably redundant */
     138           0 :     stream->state = FD_H2_STREAM_STATE_OPEN;
     139           0 :   }
     140           0 :   if( flags & FD_H2_FLAG_END_STREAM ) {
     141           0 :     fd_h2_stream_close_rx( stream, conn );
     142           0 :   }
     143           0 :   if( flags & FD_H2_FLAG_END_HEADERS ) {
     144           0 :     stream->hdrs_seq = (uchar)( stream->hdrs_seq + 1 );
     145           0 :   }
     146           0 : }
     147             : 
     148             : static inline void
     149             : fd_h2_stream_rx_data( fd_h2_stream_t * stream,
     150             :                       fd_h2_conn_t *   conn,
     151           0 :                       ulong            flags ) {
     152           0 :   if( flags & FD_H2_FLAG_END_STREAM ) {
     153           0 :     fd_h2_stream_close_rx( stream, conn );
     154           0 :   }
     155           0 : }
     156             : 
     157             : FD_PROTOTYPES_END
     158             : 
     159             : #endif /* HEADER_fd_src_waltz_h2_fd_h2_stream_h */

Generated by: LCOV version 1.14