Packages
hackney
2.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_stream.h
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
#ifndef LSQUIC_STREAM_H
#define LSQUIC_STREAM_H
#define LSQUIC_STREAM_DEFAULT_PRIO 16 /* RFC 7540, Section 5.3.5 */
struct lsquic_stream_if;
struct lsquic_stream_ctx;
struct lsquic_conn_public;
struct stream_frame;
struct uncompressed_headers;
enum enc_level;
enum swtp_status;
struct frame_gen_ctx;
struct data_frame;
enum quic_frame_type;
struct push_promise;
union hblock_ctx;
struct lsquic_packet_out;
struct lsquic_send_ctl;
struct network_path;
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
#ifndef LSQUIC_KEEP_STREAM_HISTORY
# define LSQUIC_KEEP_STREAM_HISTORY 1
#endif
#if LSQUIC_KEEP_STREAM_HISTORY
#define SM_HIST_BITS 6
#define SM_HIST_IDX_MASK ((1 << SM_HIST_BITS) - 1)
typedef unsigned char sm_hist_idx_t;
#endif
/*
* +----------+----------------------------------+
* | Low Bits | Stream Type |
* +----------+----------------------------------+
* | 0x0 | Client-Initiated, Bidirectional |
* | | |
* | 0x1 | Server-Initiated, Bidirectional |
* | | |
* | 0x2 | Client-Initiated, Unidirectional |
* | | |
* | 0x3 | Server-Initiated, Unidirectional |
* +----------+----------------------------------+
*/
enum stream_id_type
{
SIT_BIDI_CLIENT,
SIT_BIDI_SERVER,
SIT_UNI_CLIENT,
SIT_UNI_SERVER,
N_SITS
};
#define SIT_MASK (N_SITS - 1)
#define SIT_SHIFT 2
#define SD_SHIFT 1
enum stream_dir { SD_BIDI, SD_UNI, N_SDS };
struct stream_hq_frame
{
STAILQ_ENTRY(stream_hq_frame)
shf_next;
/* At which point in the stream (sm_payload) to insert the HQ frame. */
uint64_t shf_off;
union {
/* Points to the frame if SHF_FIXED_SIZE is not set */
unsigned char *frame_ptr;
/* If SHF_FIXED_SIZE is set, the size of the frame to follow.
* Non-fixed frame size gets calculated using sm_payload when they
* are closed.
*/
size_t frame_size;
} shf_u;
#define shf_frame_ptr shf_u.frame_ptr
#define shf_frame_size shf_u.frame_size
enum hq_frame_type shf_frame_type;
enum shf_flags {
SHF_TWO_BYTES = 1 << 0, /* Use two byte to encode frame length */
SHF_FIXED_SIZE = 1 << 1, /* Payload size guaranteed */
SHF_ACTIVE = 1 << 2, /* On sm_hq_frames list */
SHF_WRITTEN = 1 << 3, /* Framing bytes have been packetized */
SHF_CC_PAID = 1 << 4, /* Paid connection cap */
SHF_PHANTOM = 1 << 5, /* Phantom frame headers are not written */
} shf_flags:8;
};
struct hq_filter
{
struct varint_read2_state hqfi_vint2_state;
/* No need to copy the values: use it directly */
#define hqfi_left hqfi_vint2_state.vr2s_two
#define hqfi_type hqfi_vint2_state.vr2s_one
struct varint_read_state hqfi_vint1_state;
#define hqfi_push_id hqfi_vint1_state.value
enum {
HQFI_FLAG_UNUSED_0 = 1 << 0,
HQFI_FLAG_ERROR = 1 << 1,
HQFI_FLAG_BEGIN = 1 << 2,
HQFI_FLAG_BLOCKED = 1 << 3,
HQFI_FLAG_HEADER = 1 << 4,
HQFI_FLAG_DATA = 1 << 5,
HQFI_FLAG_TRAILER = 1 << 6,
} hqfi_flags:8;
enum {
HQFI_STATE_FRAME_HEADER_BEGIN,
HQFI_STATE_FRAME_HEADER_CONTINUE,
HQFI_STATE_READING_PAYLOAD,
HQFI_STATE_PUSH_ID_BEGIN,
HQFI_STATE_PUSH_ID_CONTINUE,
} hqfi_state:8;
};
struct stream_filter_if
{
int (*sfi_readable)(struct lsquic_stream *);
size_t (*sfi_filter_df)(struct lsquic_stream *, struct data_frame *);
void (*sfi_decr_left)(struct lsquic_stream *, size_t);
};
/* These flags indicate which queues -- or other entities -- currently
* reference the stream.
*/
enum stream_q_flags
{
/* read_streams: */
SMQF_WANT_READ = 1 << 0,
/* write_streams: */
#define SMQF_WRITE_Q_FLAGS (SMQF_WANT_FLUSH|SMQF_WANT_WRITE)
SMQF_WANT_WRITE = 1 << 1,
SMQF_WANT_FLUSH = 1 << 2, /* Flush until sm_flush_to is hit */
/* There are more than one reason that a stream may be put onto
* connections's sending_streams queue. Note that writing STREAM
* frames is done separately.
*/
#define SMQF_SENDING_FLAGS (SMQF_SEND_WUF|SMQF_SEND_RST|SMQF_SEND_BLOCKED\
|SMQF_SEND_STOP_SENDING)
/* sending_streams: */
SMQF_SEND_WUF = 1 << 3, /* WUF: Window Update Frame */
SMQF_SEND_BLOCKED = 1 << 4,
SMQF_SEND_RST = 1 << 5, /* Error: want to send RST_STREAM */
SMQF_SEND_STOP_SENDING = 1 << 10,
/* The equivalent of WINDOW_UPDATE frame for streams in IETF QUIC is
* the MAX_STREAM_DATA frame. Define an alias for use in the IETF
* QUIC code:
*/
#define SMQF_SEND_MAX_STREAM_DATA SMQF_SEND_WUF
#define SMQF_SERVICE_FLAGS (SMQF_CALL_ONCLOSE|SMQF_FREE_STREAM|SMQF_ABORT_CONN)
SMQF_CALL_ONCLOSE = 1 << 6,
SMQF_FREE_STREAM = 1 << 7,
SMQF_ABORT_CONN = 1 << 8, /* Unrecoverable error occurred */
SMQF_QPACK_DEC = 1 << 9, /* QPACK decoder handler is holding a reference to this stream */
/* The stream can reference itself, preventing its own destruction: */
#define SMQF_SELF_FLAGS SMQF_WAIT_FIN_OFF
SMQF_WAIT_FIN_OFF = 1 << 11, /* Waiting for final offset: FIN or RST */
};
/* Stream behavior flags */
enum stream_b_flags
{
SMBF_SERVER = 1 << 0,
SMBF_IETF = 1 << 1,
SMBF_USE_HEADERS = 1 << 2,
SMBF_CRYPTO = 1 << 3, /* Crypto stream: applies to both gQUIC and IETF QUIC */
SMBF_CRITICAL = 1 << 4, /* This is a critical stream */
SMBF_AUTOSWITCH = 1 << 5,
SMBF_RW_ONCE = 1 << 6, /* When set, read/write events are dispatched once per call */
SMBF_CONN_LIMITED = 1 << 7,
SMBF_HEADERS = 1 << 8, /* Headers stream */
SMBF_VERIFY_CL = 1 << 9, /* Verify content-length (stored in sm_cont_len) */
SMBF_HTTP_PRIO = 1 <<10, /* Extensible HTTP Priorities are used */
SMBF_INCREMENTAL = 1 <<11, /* Value of the "incremental" HTTP Priority parameter */
SMBF_HPRIO_SET = 1 <<12, /* Extensible HTTP Priorities have been set once */
SMBF_DELAY_ONCLOSE= 1 <<13, /* Delay calling on_close() until peer ACKs everything */
#define N_SMBF_FLAGS 14
};
/* Stream "callback done" flags */
/* TODO: move STREAM.*DONE flags from stream_flags here */
enum stream_d_flags
{
SMDF_ONRESET0 = 1 << 0, /* Called on_reset(0) */
SMDF_ONRESET1 = 1 << 1, /* Called on_reset(1) */
};
enum stream_flags {
STREAM_FIN_RECVD = 1 << 0, /* Received STREAM frame with FIN bit set */
STREAM_RST_RECVD = 1 << 1, /* Received RST frame */
STREAM_LAST_WRITE_OK= 1 << 2, /* Used to break out of write event dispatch loop */
STREAM_U_READ_DONE = 1 << 3, /* User is done reading (shutdown was called) */
STREAM_U_WRITE_DONE = 1 << 4, /* User is done writing (shutdown was called) */
STREAM_FIN_SENT = 1 << 5, /* FIN was written to network */
STREAM_RST_SENT = 1 << 6, /* RST_STREAM was written to network */
STREAM_FIN_REACHED = 1 << 7, /* User read data up to FIN */
STREAM_FINISHED = 1 << 8, /* Stream is finished */
STREAM_ONCLOSE_DONE = 1 << 9, /* on_close has been called */
STREAM_CACHED_FRAME = 1 << 10, /* If set, sm_has_frame can be used */
STREAM_HEADERS_SENT = 1 << 11,
STREAM_HAVE_UH = 1 << 12, /* Have uncompressed headers */
STREAM_ENCODER_DEP = 1 << 13, /* Encoder dependency: flush (IETF only) */
STREAM_HEAD_IN_FIN = 1 << 14, /* Incoming headers has FIN bit set */
STREAM_FRAMES_ELIDED= 1 << 15,
STREAM_FORCE_FINISH = 1 << 16, /* Replaces FIN sent and received */
STREAM_ONNEW_DONE = 1 << 17, /* on_new_stream has been called */
STREAM_PUSHING = 1 << 18,
STREAM_NOPUSH = 1 << 19, /* Disallow further push promises */
STREAM_GOAWAY_IN = 1 << 20, /* Incoming GOAWAY has been processed */
STREAM_SS_SENT = 1 << 21, /* STOP_SENDING sent */
STREAM_RST_ACKED = 1 << 22, /* Packet containing RST has been acked */
STREAM_BLOCKED_SENT = 1 << 23, /* Stays set once a STREAM_BLOCKED frame is sent */
STREAM_RST_READ = 1 << 24, /* User code collected the error */
STREAM_DATA_RECVD = 1 << 25, /* Cache stream state calculation */
STREAM_UNUSED26 = 1 << 26, /* Unused */
STREAM_HDRS_FLUSHED = 1 << 27, /* Only used in buffered packets mode */
STREAM_SS_RECVD = 1 << 28, /* Received STOP_SENDING frame */
STREAM_DELAYED_SW = 1 << 29, /* Delayed shutdown_write call */
};
/* By keeping this number low, we make sure that the code to allocate HQ
* frames dynamically gets exercised whenever push promises are sent.
*/
#define NUM_ALLOCED_HQ_FRAMES 2
struct lsquic_stream
{
struct lsquic_hash_elem sm_hash_el;
lsquic_stream_id_t id;
enum stream_flags stream_flags;
enum stream_b_flags sm_bflags;
enum stream_q_flags sm_qflags;
unsigned n_unacked;
const struct lsquic_stream_if *stream_if;
struct lsquic_stream_ctx *st_ctx;
struct lsquic_conn_public *conn_pub;
TAILQ_ENTRY(lsquic_stream) next_send_stream, next_read_stream,
next_write_stream, next_service_stream,
next_prio_stream;
uint64_t tosend_off;
uint64_t sm_payload; /* Not counting HQ frames */
uint64_t max_send_off;
uint64_t sm_last_recv_off;
uint64_t error_code;
/* From the network, we get frames, which we keep on a list ordered
* by offset.
*/
struct data_in *data_in;
uint64_t read_offset;
lsquic_sfcw_t fc;
/* List of active HQ frames */
STAILQ_HEAD(, stream_hq_frame) sm_hq_frames;
/* For efficiency, several frames are allocated as part of the stream
* itself. If more frames are needed, they are allocated.
*/
struct stream_hq_frame sm_hq_frame_arr[NUM_ALLOCED_HQ_FRAMES];
struct hq_filter sm_hq_filter;
/* Optional tap for pwritev undo */
struct hq_arr *sm_hq_arr;
/* We can safely use sm_hq_filter */
#define sm_uni_type_state sm_hq_filter.hqfi_vint2_state.vr2s_varint_state
/** If @ref SMQF_WANT_FLUSH is set, flush until this offset. */
uint64_t sm_flush_to;
/**
* If @ref SMQF_WANT_FLUSH is set, this indicates payload offset
* to flush to. Used to adjust @ref sm_flush_to when H3 frame
* size grows.
*/
uint64_t sm_flush_to_payload;
/* Last offset sent in BLOCKED frame */
uint64_t blocked_off;
struct uncompressed_headers *uh,
*push_req;
union hblock_ctx *sm_hblock_ctx;
unsigned char *sm_buf;
void *sm_onnew_arg;
unsigned char *sm_header_block;
uint64_t sm_hb_compl;
/* Valid if STREAM_FIN_RECVD is set: */
uint64_t sm_fin_off;
/* A stream may be generating STREAM or CRYPTO frames */
size_t (*sm_frame_header_sz)(
const struct lsquic_stream *, unsigned);
enum swtp_status (*sm_write_to_packet)(struct frame_gen_ctx *,
const size_t);
size_t (*sm_write_avail)(struct lsquic_stream *);
int (*sm_readable)(struct lsquic_stream *);
struct lsquic_packet_out * (*sm_get_packet_for_stream)(
struct lsquic_send_ctl *,
unsigned, const struct network_path *,
const struct lsquic_stream *);
/* This element is optional */
const struct stream_filter_if *sm_sfi;
/* sm_promise and sm_promises are never used at the same time and can
* be combined into a union should space in this struct become tight.
*/
/* Push promise that engendered this push stream */
struct push_promise *sm_promise;
/* Push promises sent on this stream */
SLIST_HEAD(, push_promise) sm_promises;
uint64_t sm_last_frame_off;
#ifndef NDEBUG
/* Last time stream made progress */
lsquic_time_t sm_last_prog;
#endif
/* Content length specified in incoming `content-length' header field.
* Used to verify size of DATA frames.
*/
unsigned long long sm_cont_len;
/* Sum of bytes in all incoming DATA frames. Used for verification. */
unsigned long long sm_data_in;
/* How much data there is in sm_header_block and how much of it has been
* sent:
*/
unsigned sm_hblock_sz,
sm_hblock_off;
unsigned short sm_n_buffered; /* Amount of data in sm_buf */
unsigned short sm_n_allocated; /* Size of sm_buf */
/* If SMBF_HTTP_PRIO is set, the priority is used to represent the
* Extensible Priority urgency, which is in the range [0, 7].
*/
unsigned char sm_priority; /* 0: high; 255: low */
unsigned char sm_enc_level;
enum {
SSHS_BEGIN, /* Nothing has happened yet */
SSHS_ENC_SENDING, /* Sending encoder stream data */
SSHS_HBLOCK_SENDING,/* Sending header block data */
} sm_send_headers_state:8;
enum stream_d_flags sm_dflags:8;
signed char sm_saved_want_write;
signed char sm_has_frame;
#if LSQUIC_KEEP_STREAM_HISTORY
sm_hist_idx_t sm_hist_idx;
#endif
#if LSQUIC_KEEP_STREAM_HISTORY
/* Stream history: see enum stream_history_event */
unsigned char sm_hist_buf[ 1 << SM_HIST_BITS ];
#endif
};
enum stream_ctor_flags
{
SCF_CALL_ON_NEW = (1 << (N_SMBF_FLAGS + 0)), /* Call on_new_stream() immediately */
SCF_USE_DI_HASH = (1 << (N_SMBF_FLAGS + 1)), /* Use hash-based data input. If not set,
* the nocopy data input is used.
*/
SCF_CRYPTO_FRAMES = (1 << (N_SMBF_FLAGS + 2)), /* Write CRYPTO frames */
SCF_DI_AUTOSWITCH = SMBF_AUTOSWITCH, /* Automatically switch between nocopy
* and hash-based to data input for optimal
* performance.
*/
SCF_DISP_RW_ONCE = SMBF_RW_ONCE,
SCF_CRITICAL = SMBF_CRITICAL, /* This is a critical stream */
SCF_IETF = SMBF_IETF,
SCF_HTTP = SMBF_USE_HEADERS,
SCF_CRYPTO = SMBF_CRYPTO,
SCF_HEADERS = SMBF_HEADERS,
SCF_HTTP_PRIO = SMBF_HTTP_PRIO,
SCF_DELAY_ONCLOSE = SMBF_DELAY_ONCLOSE,
};
lsquic_stream_t *
lsquic_stream_new (lsquic_stream_id_t id, struct lsquic_conn_public *,
const struct lsquic_stream_if *, void *stream_if_ctx,
unsigned initial_sfrw, uint64_t initial_send_off,
enum stream_ctor_flags);
struct lsquic_stream *
lsquic_stream_new_crypto (enum enc_level,
struct lsquic_conn_public *conn_pub,
const struct lsquic_stream_if *stream_if, void *stream_if_ctx,
enum stream_ctor_flags ctor_flags);
void
lsquic_stream_call_on_new (lsquic_stream_t *);
void
lsquic_stream_destroy (lsquic_stream_t *);
/* True if either read or write side of the stream has been reset */
#define lsquic_stream_is_reset(stream) \
(((stream)->stream_flags & \
(STREAM_RST_RECVD|STREAM_RST_SENT|STREAM_SS_RECVD)) \
|| ((stream)->sm_qflags & SMQF_SEND_RST))
int
lsquic_stream_is_write_reset (const struct lsquic_stream *);
/* Data that from the network gets inserted into the stream using
* lsquic_stream_frame_in() function. Returns 0 on success, -1 on
* failure. The latter may be caused by flow control violation or
* invalid stream frame data, e.g. overlapping segments.
*
* Note that the caller gives up control of `frame' no matter
* what this function returns.
*
* This data is read by the user using lsquic_stream_read() function.
*/
int
lsquic_stream_frame_in (lsquic_stream_t *, struct stream_frame *frame);
/* Only one (at least for now) uncompressed header structure is allowed to be
* passed in, and only in HTTP mode.
*/
int
lsquic_stream_uh_in (lsquic_stream_t *, struct uncompressed_headers *);
void
lsquic_stream_push_req (lsquic_stream_t *,
struct uncompressed_headers *push_req);
int
lsquic_stream_rst_in (lsquic_stream_t *, uint64_t offset, uint64_t error_code);
void
lsquic_stream_stop_sending_in (struct lsquic_stream *, uint64_t error_code);
uint64_t
lsquic_stream_read_offset (const lsquic_stream_t *stream);
/* Return true if we sent all available data to the network and write
* end of the stream was closed.
*/
int
lsquic_stream_tosend_fin (const lsquic_stream_t *stream);
void
lsquic_stream_window_update (lsquic_stream_t *stream, uint64_t offset);
int
lsquic_stream_set_max_send_off (lsquic_stream_t *stream, uint64_t offset);
/* The caller should only call this function if SMQF_SEND_WUF is set and
* it must generate a window update frame using this value.
*/
uint64_t
lsquic_stream_fc_recv_off (lsquic_stream_t *stream);
void
lsquic_stream_peer_blocked (struct lsquic_stream *, uint64_t);
void
lsquic_stream_peer_blocked_gquic (struct lsquic_stream *);
void
lsquic_stream_dispatch_read_events (lsquic_stream_t *);
void
lsquic_stream_dispatch_write_events (lsquic_stream_t *);
void
lsquic_stream_blocked_frame_sent (lsquic_stream_t *);
void
lsquic_stream_rst_frame_sent (lsquic_stream_t *);
void
lsquic_stream_stream_frame_sent (lsquic_stream_t *);
void
lsquic_stream_maybe_reset (struct lsquic_stream *, uint64_t error_code, int);
void
lsquic_stream_call_on_close (lsquic_stream_t *);
void
lsquic_stream_shutdown_internal (lsquic_stream_t *);
void
lsquic_stream_received_goaway (lsquic_stream_t *);
void
lsquic_stream_acked (struct lsquic_stream *, enum quic_frame_type);
#define lsquic_stream_is_closed(s) \
(((s)->stream_flags & (STREAM_U_READ_DONE|STREAM_U_WRITE_DONE)) \
== (STREAM_U_READ_DONE|STREAM_U_WRITE_DONE))
int
lsquic_stream_update_sfcw (lsquic_stream_t *, uint64_t max_off);
int
lsquic_stream_set_priority_internal (lsquic_stream_t *, unsigned priority);
#define lsquic_stream_is_critical(s) ((s)->sm_bflags & SMBF_CRITICAL)
#define lsquic_stream_is_crypto(s) ((s)->sm_bflags & SMBF_CRYPTO)
size_t
lsquic_stream_mem_used (const struct lsquic_stream *);
const lsquic_cid_t *
lsquic_stream_cid (const struct lsquic_stream *);
#define lsquic_stream_has_data_to_flush(stream) ((stream)->sm_n_buffered > 0)
int
lsquic_stream_readable (struct lsquic_stream *);
size_t
lsquic_stream_write_avail (struct lsquic_stream *);
void
lsquic_stream_dump_state (const struct lsquic_stream *);
#ifndef NDEBUG
size_t
lsquic_stream_flush_threshold (const struct lsquic_stream *, unsigned);
#endif
#define crypto_level(stream) (UINT64_MAX - (stream)->id)
void
lsquic_stream_set_stream_if (struct lsquic_stream *,
const struct lsquic_stream_if *, void *stream_if_ctx);
uint64_t
lsquic_stream_combined_send_off (const struct lsquic_stream *);
/* [draft-ietf-quic-transport-16] Section 3.1 */
enum stream_state_sending
{
SSS_READY,
SSS_SEND,
SSS_DATA_SENT,
SSS_RESET_SENT,
SSS_DATA_RECVD,
SSS_RESET_RECVD,
};
extern const char *const lsquic_sss2str[];
enum stream_state_sending
lsquic_stream_sending_state (const struct lsquic_stream *);
/* [draft-ietf-quic-transport-16] Section 3.2 */
enum stream_state_receiving
{
SSR_RECV,
SSR_SIZE_KNOWN,
SSR_DATA_RECVD,
SSR_RESET_RECVD,
SSR_DATA_READ,
SSR_RESET_READ,
};
extern const char *const lsquic_ssr2str[];
enum stream_state_receiving
lsquic_stream_receiving_state (struct lsquic_stream *);
uint64_t
lsquic_stream_fc_recv_off_const (const struct lsquic_stream *);
void
lsquic_stream_max_stream_data_sent (struct lsquic_stream *);
void
lsquic_stream_qdec_unblocked (struct lsquic_stream *);
int
lsquic_stream_can_push (const struct lsquic_stream *);
int
lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);
void
lsquic_stream_force_finish (struct lsquic_stream *);
int
lsquic_stream_header_is_pp (const struct lsquic_stream *);
int
lsquic_stream_header_is_trailer (const struct lsquic_stream *);
int
lsquic_stream_verify_len (struct lsquic_stream *, unsigned long long);
#define lsquic_stream_is_blocked(stream_) ((stream_)->blocked_off && \
(stream_)->blocked_off == (stream_)->max_send_off)
void
lsquic_stream_ss_frame_sent (struct lsquic_stream *);
#ifndef NDEBUG
void
lsquic_stream_set_pwritev_params (unsigned iovecs, unsigned frames);
#endif
void
lsquic_stream_drop_hset_ref (struct lsquic_stream *);
#endif