lsquic_stream.h revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#ifndef LSQUIC_STREAM_H
3#define LSQUIC_STREAM_H
4
5#define LSQUIC_STREAM_DEFAULT_PRIO 16   /* RFC 7540, Section 5.3.5 */
6
7
8struct lsquic_stream_if;
9struct lsquic_stream_ctx;
10struct lsquic_conn_public;
11struct stream_frame;
12struct uncompressed_headers;
13enum enc_level;
14enum swtp_status;
15struct frame_gen_ctx;
16struct data_frame;
17enum quic_frame_type;
18struct push_promise;
19union hblock_ctx;
20struct lsquic_packet_out;
21struct lsquic_send_ctl;
22struct network_path;
23
24TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
25
26
27#ifndef LSQUIC_KEEP_STREAM_HISTORY
28#   define LSQUIC_KEEP_STREAM_HISTORY 1
29#endif
30
31
32#if LSQUIC_KEEP_STREAM_HISTORY
33#define SM_HIST_BITS 6
34#define SM_HIST_IDX_MASK ((1 << SM_HIST_BITS) - 1)
35typedef unsigned char sm_hist_idx_t;
36#endif
37
38
39/*
40 *  +----------+----------------------------------+
41 *  | Low Bits | Stream Type                      |
42 *  +----------+----------------------------------+
43 *  | 0x0      | Client-Initiated, Bidirectional  |
44 *  |          |                                  |
45 *  | 0x1      | Server-Initiated, Bidirectional  |
46 *  |          |                                  |
47 *  | 0x2      | Client-Initiated, Unidirectional |
48 *  |          |                                  |
49 *  | 0x3      | Server-Initiated, Unidirectional |
50 *  +----------+----------------------------------+
51 */
52
53enum stream_id_type
54{
55    SIT_BIDI_CLIENT,
56    SIT_BIDI_SERVER,
57    SIT_UNI_CLIENT,
58    SIT_UNI_SERVER,
59    N_SITS
60};
61
62#define SIT_MASK (N_SITS - 1)
63
64#define SIT_SHIFT 2
65#define SD_SHIFT 1
66
67enum stream_dir { SD_BIDI, SD_UNI, N_SDS };
68
69
70struct stream_hq_frame
71{
72    STAILQ_ENTRY(stream_hq_frame)
73                        shf_next;
74    /* At which point in the stream (sm_payload) to insert the HQ frame. */
75    uint64_t            shf_off;
76    union {
77        /* Points to the frame if SHF_FIXED_SIZE is not set */
78        unsigned char  *frame_ptr;
79        /* If SHF_FIXED_SIZE is set, the size of the frame to follow.
80         * Non-fixed frame size gets calculated using sm_payload when they
81         * are closed.
82         */
83        size_t          frame_size;
84    }                   shf_u;
85#define shf_frame_ptr shf_u.frame_ptr
86#define shf_frame_size shf_u.frame_size
87    enum hq_frame_type  shf_frame_type;
88    enum shf_flags {
89        SHF_TWO_BYTES   = 1 << 0,   /* Use two byte to encode frame length */
90        SHF_FIXED_SIZE  = 1 << 1,   /* Payload size guaranteed */
91        SHF_ACTIVE      = 1 << 2,   /* On sm_hq_frames list */
92        SHF_WRITTEN     = 1 << 3,   /* Framing bytes have been packetized */
93        SHF_CC_PAID     = 1 << 4,   /* Paid connection cap */
94        SHF_PHANTOM     = 1 << 5,   /* Phantom frame headers are not written */
95    }                   shf_flags:8;
96};
97
98
99struct hq_filter
100{
101    struct varint_read2_state   hqfi_vint2_state;
102    /* No need to copy the values: use it directly */
103#define hqfi_left hqfi_vint2_state.vr2s_two
104#define hqfi_type hqfi_vint2_state.vr2s_one
105    struct varint_read_state    hqfi_vint1_state;
106#define hqfi_push_id hqfi_vint1_state.value
107    enum {
108        HQFI_FLAG_UNUSED_0      = 1 << 0,
109        HQFI_FLAG_ERROR         = 1 << 1,
110        HQFI_FLAG_BEGIN         = 1 << 2,
111        HQFI_FLAG_BLOCKED       = 1 << 3,
112        HQFI_FLAG_HEADER        = 1 << 4,
113        HQFI_FLAG_DATA          = 1 << 5,
114        HQFI_FLAG_TRAILER       = 1 << 6,
115    }                           hqfi_flags:8;
116    enum {
117        HQFI_STATE_FRAME_HEADER_BEGIN,
118        HQFI_STATE_FRAME_HEADER_CONTINUE,
119        HQFI_STATE_READING_PAYLOAD,
120        HQFI_STATE_PUSH_ID_BEGIN,
121        HQFI_STATE_PUSH_ID_CONTINUE,
122    }                           hqfi_state:8;
123};
124
125
126struct stream_filter_if
127{
128    int         (*sfi_readable)(struct lsquic_stream *);
129    size_t      (*sfi_filter_df)(struct lsquic_stream *, struct data_frame *);
130    void        (*sfi_decr_left)(struct lsquic_stream *, size_t);
131};
132
133
134/* These flags indicate which queues -- or other entities -- currently
135 * reference the stream.
136 */
137enum stream_q_flags
138{
139    /* read_streams: */
140    SMQF_WANT_READ    = 1 << 0,
141
142    /* write_streams: */
143#define SMQF_WRITE_Q_FLAGS (SMQF_WANT_FLUSH|SMQF_WANT_WRITE)
144    SMQF_WANT_WRITE   = 1 << 1,
145    SMQF_WANT_FLUSH   = 1 << 2,     /* Flush until sm_flush_to is hit */
146
147    /* There are more than one reason that a stream may be put onto
148     * connections's sending_streams queue.  Note that writing STREAM
149     * frames is done separately.
150     */
151#define SMQF_SENDING_FLAGS (SMQF_SEND_WUF|SMQF_SEND_RST|SMQF_SEND_BLOCKED\
152                                                    |SMQF_SEND_STOP_SENDING)
153    /* sending_streams: */
154    SMQF_SEND_WUF     = 1 << 3,     /* WUF: Window Update Frame */
155    SMQF_SEND_BLOCKED = 1 << 4,
156    SMQF_SEND_RST     = 1 << 5,     /* Error: want to send RST_STREAM */
157    SMQF_SEND_STOP_SENDING = 1 << 10,
158
159    /* The equivalent of WINDOW_UPDATE frame for streams in IETF QUIC is
160     * the MAX_STREAM_DATA frame.  Define an alias for use in the IETF
161     * QUIC code:
162     */
163#define SMQF_SEND_MAX_STREAM_DATA SMQF_SEND_WUF
164
165#define SMQF_SERVICE_FLAGS (SMQF_CALL_ONCLOSE|SMQF_FREE_STREAM|SMQF_ABORT_CONN)
166    SMQF_CALL_ONCLOSE = 1 << 6,
167    SMQF_FREE_STREAM  = 1 << 7,
168    SMQF_ABORT_CONN   = 1 << 8,     /* Unrecoverable error occurred */
169
170    SMQF_QPACK_DEC    = 1 << 9,     /* QPACK decoder handler is holding a reference to this stream */
171
172    /* The stream can reference itself, preventing its own destruction: */
173#define SMQF_SELF_FLAGS SMQF_WAIT_FIN_OFF
174    SMQF_WAIT_FIN_OFF = 1 << 11,    /* Waiting for final offset: FIN or RST */
175};
176
177
178/* Stream behavior flags */
179enum stream_b_flags
180{
181    SMBF_SERVER       = 1 << 0,
182    SMBF_IETF         = 1 << 1,
183    SMBF_USE_HEADERS  = 1 << 2,
184    SMBF_CRYPTO       = 1 << 3,  /* Crypto stream: applies to both gQUIC and IETF QUIC */
185    SMBF_CRITICAL     = 1 << 4,  /* This is a critical stream */
186    SMBF_AUTOSWITCH   = 1 << 5,
187    SMBF_RW_ONCE      = 1 << 6,  /* When set, read/write events are dispatched once per call */
188    SMBF_CONN_LIMITED = 1 << 7,
189    SMBF_HEADERS      = 1 << 8,  /* Headers stream */
190    SMBF_VERIFY_CL    = 1 << 9,  /* Verify content-length (stored in sm_cont_len) */
191    SMBF_HTTP_PRIO    = 1 <<10,  /* Extensible HTTP Priorities are used */
192    SMBF_INCREMENTAL  = 1 <<11,  /* Value of the "incremental" HTTP Priority parameter */
193    SMBF_HPRIO_SET    = 1 <<12,  /* Extensible HTTP Priorities have been set once */
194    SMBF_DELAY_ONCLOSE= 1 <<13,  /* Delay calling on_close() until peer ACKs everything */
195#define N_SMBF_FLAGS 14
196};
197
198
199/* Stream "callback done" flags */
200/* TODO: move STREAM.*DONE flags from stream_flags here */
201enum stream_d_flags
202{
203    SMDF_ONRESET0       =   1 << 0, /* Called on_reset(0) */
204    SMDF_ONRESET1       =   1 << 1, /* Called on_reset(1) */
205};
206
207
208enum stream_flags {
209    STREAM_FIN_RECVD    = 1 << 0,   /* Received STREAM frame with FIN bit set */
210    STREAM_RST_RECVD    = 1 << 1,   /* Received RST frame */
211    STREAM_LAST_WRITE_OK= 1 << 2,   /* Used to break out of write event dispatch loop */
212    STREAM_U_READ_DONE  = 1 << 3,   /* User is done reading (shutdown was called) */
213    STREAM_U_WRITE_DONE = 1 << 4,   /* User is done writing (shutdown was called) */
214    STREAM_FIN_SENT     = 1 << 5,   /* FIN was written to network */
215    STREAM_RST_SENT     = 1 << 6,   /* RST_STREAM was written to network */
216    STREAM_FIN_REACHED  = 1 << 7,   /* User read data up to FIN */
217    STREAM_FINISHED     = 1 << 8,   /* Stream is finished */
218    STREAM_ONCLOSE_DONE = 1 << 9,   /* on_close has been called */
219    STREAM_CACHED_FRAME = 1 << 10,  /* If set, sm_has_frame can be used */
220    STREAM_HEADERS_SENT = 1 << 11,
221    STREAM_HAVE_UH      = 1 << 12,  /* Have uncompressed headers */
222    STREAM_ENCODER_DEP  = 1 << 13,  /* Encoder dependency: flush (IETF only) */
223    STREAM_HEAD_IN_FIN  = 1 << 14,  /* Incoming headers has FIN bit set */
224    STREAM_FRAMES_ELIDED= 1 << 15,
225    STREAM_FORCE_FINISH = 1 << 16,  /* Replaces FIN sent and received */
226    STREAM_ONNEW_DONE   = 1 << 17,  /* on_new_stream has been called */
227    STREAM_PUSHING      = 1 << 18,
228    STREAM_NOPUSH       = 1 << 19,  /* Disallow further push promises */
229    STREAM_GOAWAY_IN    = 1 << 20,  /* Incoming GOAWAY has been processed */
230    STREAM_SS_SENT      = 1 << 21,  /* STOP_SENDING sent */
231    STREAM_RST_ACKED    = 1 << 22,  /* Packet containing RST has been acked */
232    STREAM_BLOCKED_SENT = 1 << 23,  /* Stays set once a STREAM_BLOCKED frame is sent */
233    STREAM_RST_READ     = 1 << 24,  /* User code collected the error */
234    STREAM_DATA_RECVD   = 1 << 25,  /* Cache stream state calculation */
235    STREAM_UNUSED26     = 1 << 26,  /* Unused */
236    STREAM_HDRS_FLUSHED = 1 << 27,  /* Only used in buffered packets mode */
237    STREAM_SS_RECVD     = 1 << 28,  /* Received STOP_SENDING frame */
238    STREAM_DELAYED_SW   = 1 << 29,  /* Delayed shutdown_write call */
239};
240
241
242/* By keeping this number low, we make sure that the code to allocate HQ
243 * frames dynamically gets exercised whenever push promises are sent.
244 */
245#define NUM_ALLOCED_HQ_FRAMES 2
246
247
248struct lsquic_stream
249{
250    struct lsquic_hash_elem         sm_hash_el;
251    lsquic_stream_id_t              id;
252    enum stream_flags               stream_flags;
253    enum stream_b_flags             sm_bflags;
254    enum stream_q_flags             sm_qflags;
255    unsigned                        n_unacked;
256
257    const struct lsquic_stream_if  *stream_if;
258    struct lsquic_stream_ctx       *st_ctx;
259    struct lsquic_conn_public      *conn_pub;
260    TAILQ_ENTRY(lsquic_stream)      next_send_stream, next_read_stream,
261                                        next_write_stream, next_service_stream,
262                                        next_prio_stream;
263
264    uint64_t                        tosend_off;
265    uint64_t                        sm_payload;     /* Not counting HQ frames */
266    uint64_t                        max_send_off;
267    uint64_t                        sm_last_recv_off;
268    uint64_t                        error_code;
269
270    /* From the network, we get frames, which we keep on a list ordered
271     * by offset.
272     */
273    struct data_in                 *data_in;
274    uint64_t                        read_offset;
275    lsquic_sfcw_t                   fc;
276
277    /* List of active HQ frames */
278    STAILQ_HEAD(, stream_hq_frame)  sm_hq_frames;
279
280    /* For efficiency, several frames are allocated as part of the stream
281     * itself.  If more frames are needed, they are allocated.
282     */
283    struct stream_hq_frame          sm_hq_frame_arr[NUM_ALLOCED_HQ_FRAMES];
284
285    struct hq_filter                sm_hq_filter;
286
287    /* Optional tap for pwritev undo */
288    struct hq_arr                  *sm_hq_arr;
289
290    /* We can safely use sm_hq_filter */
291#define sm_uni_type_state sm_hq_filter.hqfi_vint2_state.vr2s_varint_state
292
293    /** If @ref SMQF_WANT_FLUSH is set, flush until this offset. */
294    uint64_t                        sm_flush_to;
295
296    /**
297     * If @ref SMQF_WANT_FLUSH is set, this indicates payload offset
298     * to flush to.  Used to adjust @ref sm_flush_to when H3 frame
299     * size grows.
300     */
301    uint64_t                        sm_flush_to_payload;
302
303    /* Last offset sent in BLOCKED frame */
304    uint64_t                        blocked_off;
305
306    struct uncompressed_headers    *uh,
307                                   *push_req;
308    union hblock_ctx               *sm_hblock_ctx;
309
310    unsigned char                  *sm_buf;
311    void                           *sm_onnew_arg;
312
313    unsigned char                  *sm_header_block;
314    uint64_t                        sm_hb_compl;
315
316    /* Valid if STREAM_FIN_RECVD is set: */
317    uint64_t                        sm_fin_off;
318
319    /* A stream may be generating STREAM or CRYPTO frames */
320    size_t                        (*sm_frame_header_sz)(
321                                        const struct lsquic_stream *, unsigned);
322    enum swtp_status              (*sm_write_to_packet)(struct frame_gen_ctx *,
323                                                const size_t);
324    size_t                        (*sm_write_avail)(struct lsquic_stream *);
325    int                           (*sm_readable)(struct lsquic_stream *);
326
327    struct lsquic_packet_out *    (*sm_get_packet_for_stream)(
328                                        struct lsquic_send_ctl *,
329                                        unsigned, const struct network_path *,
330                                        const struct lsquic_stream *);
331
332    /* This element is optional */
333    const struct stream_filter_if  *sm_sfi;
334
335    /* sm_promise and sm_promises are never used at the same time and can
336     * be combined into a union should space in this struct become tight.
337     */
338    /* Push promise that engendered this push stream */
339    struct push_promise            *sm_promise;
340
341    /* Push promises sent on this stream */
342    SLIST_HEAD(, push_promise)      sm_promises;
343
344    uint64_t                        sm_last_frame_off;
345
346#ifndef NDEBUG
347    /* Last time stream made progress */
348    lsquic_time_t                   sm_last_prog;
349#endif
350
351    /* Content length specified in incoming `content-length' header field.
352     * Used to verify size of DATA frames.
353     */
354    unsigned long long              sm_cont_len;
355    /* Sum of bytes in all incoming DATA frames.  Used for verification. */
356    unsigned long long              sm_data_in;
357
358    /* How much data there is in sm_header_block and how much of it has been
359     * sent:
360     */
361    unsigned                        sm_hblock_sz,
362                                    sm_hblock_off;
363
364    unsigned short                  sm_n_buffered;  /* Amount of data in sm_buf */
365    unsigned short                  sm_n_allocated;  /* Size of sm_buf */
366
367    /* If SMBF_HTTP_PRIO is set, the priority is used to represent the
368     * Extensible Priority urgency, which is in the range [0, 7].
369     */
370    unsigned char                   sm_priority;  /* 0: high; 255: low */
371    unsigned char                   sm_enc_level;
372    enum {
373        SSHS_BEGIN,         /* Nothing has happened yet */
374        SSHS_ENC_SENDING,   /* Sending encoder stream data */
375        SSHS_HBLOCK_SENDING,/* Sending header block data */
376    }                               sm_send_headers_state:8;
377    enum stream_d_flags             sm_dflags:8;
378    signed char                     sm_saved_want_write;
379    signed char                     sm_has_frame;
380
381#if LSQUIC_KEEP_STREAM_HISTORY
382    sm_hist_idx_t                   sm_hist_idx;
383#endif
384
385#if LSQUIC_KEEP_STREAM_HISTORY
386    /* Stream history: see enum stream_history_event */
387    unsigned char                   sm_hist_buf[ 1 << SM_HIST_BITS ];
388#endif
389};
390
391
392enum stream_ctor_flags
393{
394    SCF_CALL_ON_NEW   = (1 << (N_SMBF_FLAGS + 0)), /* Call on_new_stream() immediately */
395    SCF_USE_DI_HASH   = (1 << (N_SMBF_FLAGS + 1)), /* Use hash-based data input.  If not set,
396                                   * the nocopy data input is used.
397                                   */
398    SCF_CRYPTO_FRAMES = (1 << (N_SMBF_FLAGS + 2)), /* Write CRYPTO frames */
399    SCF_DI_AUTOSWITCH = SMBF_AUTOSWITCH, /* Automatically switch between nocopy
400                                   * and hash-based to data input for optimal
401                                   * performance.
402                                   */
403    SCF_DISP_RW_ONCE  = SMBF_RW_ONCE,
404    SCF_CRITICAL      = SMBF_CRITICAL, /* This is a critical stream */
405    SCF_IETF          = SMBF_IETF,
406    SCF_HTTP          = SMBF_USE_HEADERS,
407    SCF_CRYPTO        = SMBF_CRYPTO,
408    SCF_HEADERS       = SMBF_HEADERS,
409    SCF_HTTP_PRIO     = SMBF_HTTP_PRIO,
410    SCF_DELAY_ONCLOSE = SMBF_DELAY_ONCLOSE,
411};
412
413
414lsquic_stream_t *
415lsquic_stream_new (lsquic_stream_id_t id, struct lsquic_conn_public *,
416                   const struct lsquic_stream_if *, void *stream_if_ctx,
417                   unsigned initial_sfrw, uint64_t initial_send_off,
418                   enum stream_ctor_flags);
419
420struct lsquic_stream *
421lsquic_stream_new_crypto (enum enc_level,
422        struct lsquic_conn_public *conn_pub,
423        const struct lsquic_stream_if *stream_if, void *stream_if_ctx,
424        enum stream_ctor_flags ctor_flags);
425
426void
427lsquic_stream_call_on_new (lsquic_stream_t *);
428
429void
430lsquic_stream_destroy (lsquic_stream_t *);
431
432/* True if either read or write side of the stream has been reset */
433#define lsquic_stream_is_reset(stream) \
434    (((stream)->stream_flags & \
435                    (STREAM_RST_RECVD|STREAM_RST_SENT|STREAM_SS_RECVD)) \
436        || ((stream)->sm_qflags & SMQF_SEND_RST))
437
438int
439lsquic_stream_is_write_reset (const struct lsquic_stream *);
440
441/* Data that from the network gets inserted into the stream using
442 * lsquic_stream_frame_in() function.  Returns 0 on success, -1 on
443 * failure.  The latter may be caused by flow control violation or
444 * invalid stream frame data, e.g. overlapping segments.
445 *
446 * Note that the caller gives up control of `frame' no matter
447 * what this function returns.
448 *
449 * This data is read by the user using lsquic_stream_read() function.
450 */
451int
452lsquic_stream_frame_in (lsquic_stream_t *, struct stream_frame *frame);
453
454/* Only one (at least for now) uncompressed header structure is allowed to be
455 * passed in, and only in HTTP mode.
456 */
457int
458lsquic_stream_uh_in (lsquic_stream_t *, struct uncompressed_headers *);
459
460void
461lsquic_stream_push_req (lsquic_stream_t *,
462                        struct uncompressed_headers *push_req);
463
464int
465lsquic_stream_rst_in (lsquic_stream_t *, uint64_t offset, uint64_t error_code);
466
467void
468lsquic_stream_stop_sending_in (struct lsquic_stream *, uint64_t error_code);
469
470uint64_t
471lsquic_stream_read_offset (const lsquic_stream_t *stream);
472
473/* Return true if we sent all available data to the network and write
474 * end of the stream was closed.
475 */
476int
477lsquic_stream_tosend_fin (const lsquic_stream_t *stream);
478
479void
480lsquic_stream_window_update (lsquic_stream_t *stream, uint64_t offset);
481
482int
483lsquic_stream_set_max_send_off (lsquic_stream_t *stream, uint64_t offset);
484
485/* The caller should only call this function if SMQF_SEND_WUF is set and
486 * it must generate a window update frame using this value.
487 */
488uint64_t
489lsquic_stream_fc_recv_off (lsquic_stream_t *stream);
490
491void
492lsquic_stream_peer_blocked (struct lsquic_stream *, uint64_t);
493
494void
495lsquic_stream_peer_blocked_gquic (struct lsquic_stream *);
496
497void
498lsquic_stream_dispatch_read_events (lsquic_stream_t *);
499
500void
501lsquic_stream_dispatch_write_events (lsquic_stream_t *);
502
503void
504lsquic_stream_blocked_frame_sent (lsquic_stream_t *);
505
506void
507lsquic_stream_rst_frame_sent (lsquic_stream_t *);
508
509void
510lsquic_stream_stream_frame_sent (lsquic_stream_t *);
511
512void
513lsquic_stream_maybe_reset (struct lsquic_stream *, uint64_t error_code, int);
514
515void
516lsquic_stream_call_on_close (lsquic_stream_t *);
517
518void
519lsquic_stream_shutdown_internal (lsquic_stream_t *);
520
521void
522lsquic_stream_received_goaway (lsquic_stream_t *);
523
524void
525lsquic_stream_acked (struct lsquic_stream *, enum quic_frame_type);
526
527#define lsquic_stream_is_closed(s)                                          \
528    (((s)->stream_flags & (STREAM_U_READ_DONE|STREAM_U_WRITE_DONE))         \
529                            == (STREAM_U_READ_DONE|STREAM_U_WRITE_DONE))
530int
531lsquic_stream_update_sfcw (lsquic_stream_t *, uint64_t max_off);
532
533int
534lsquic_stream_set_priority_internal (lsquic_stream_t *, unsigned priority);
535
536#define lsquic_stream_is_critical(s) ((s)->sm_bflags & SMBF_CRITICAL)
537
538#define lsquic_stream_is_crypto(s) ((s)->sm_bflags & SMBF_CRYPTO)
539
540size_t
541lsquic_stream_mem_used (const struct lsquic_stream *);
542
543const lsquic_cid_t *
544lsquic_stream_cid (const struct lsquic_stream *);
545
546#define lsquic_stream_has_data_to_flush(stream) ((stream)->sm_n_buffered > 0)
547
548int
549lsquic_stream_readable (struct lsquic_stream *);
550
551size_t
552lsquic_stream_write_avail (struct lsquic_stream *);
553
554void
555lsquic_stream_dump_state (const struct lsquic_stream *);
556
557#ifndef NDEBUG
558size_t
559lsquic_stream_flush_threshold (const struct lsquic_stream *, unsigned);
560#endif
561
562#define crypto_level(stream) (UINT64_MAX - (stream)->id)
563
564void
565lsquic_stream_set_stream_if (struct lsquic_stream *,
566                   const struct lsquic_stream_if *, void *stream_if_ctx);
567
568uint64_t
569lsquic_stream_combined_send_off (const struct lsquic_stream *);
570
571/* [draft-ietf-quic-transport-16] Section 3.1 */
572enum stream_state_sending
573{
574    SSS_READY,
575    SSS_SEND,
576    SSS_DATA_SENT,
577    SSS_RESET_SENT,
578    SSS_DATA_RECVD,
579    SSS_RESET_RECVD,
580};
581
582extern const char *const lsquic_sss2str[];
583
584enum stream_state_sending
585lsquic_stream_sending_state (const struct lsquic_stream *);
586
587/* [draft-ietf-quic-transport-16] Section 3.2 */
588enum stream_state_receiving
589{
590    SSR_RECV,
591    SSR_SIZE_KNOWN,
592    SSR_DATA_RECVD,
593    SSR_RESET_RECVD,
594    SSR_DATA_READ,
595    SSR_RESET_READ,
596};
597
598extern const char *const lsquic_ssr2str[];
599
600enum stream_state_receiving
601lsquic_stream_receiving_state (struct lsquic_stream *);
602
603uint64_t
604lsquic_stream_fc_recv_off_const (const struct lsquic_stream *);
605
606void
607lsquic_stream_max_stream_data_sent (struct lsquic_stream *);
608
609void
610lsquic_stream_qdec_unblocked (struct lsquic_stream *);
611
612int
613lsquic_stream_can_push (const struct lsquic_stream *);
614
615int
616lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);
617
618void
619lsquic_stream_force_finish (struct lsquic_stream *);
620
621int
622lsquic_stream_header_is_pp (const struct lsquic_stream *);
623
624int
625lsquic_stream_header_is_trailer (const struct lsquic_stream *);
626
627int
628lsquic_stream_verify_len (struct lsquic_stream *, unsigned long long);
629
630#define lsquic_stream_is_blocked(stream_) ((stream_)->blocked_off && \
631                        (stream_)->blocked_off == (stream_)->max_send_off)
632
633void
634lsquic_stream_ss_frame_sent (struct lsquic_stream *);
635
636#ifndef NDEBUG
637void
638lsquic_stream_set_pwritev_params (unsigned iovecs, unsigned frames);
639#endif
640
641void
642lsquic_stream_drop_hset_ref (struct lsquic_stream *);
643
644#endif
645