mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.6.7
- [FEATURE] Implement the QL extension (offered by default). - [BUGFIX] Abort when encountering unexpected HTTP/3 frames. - [BUGFIX] Acknowledge (QPACK) HTTP/3 trailers correctly. - [DEBUG] Turn on debug message for next advisory tick.
This commit is contained in:
parent
55f8042d41
commit
02b6086dba
18 changed files with 317 additions and 49 deletions
|
@ -1,3 +1,10 @@
|
|||
2019-11-22
|
||||
- 2.6.7
|
||||
- [FEATURE] Implement the QL extension (offered by default).
|
||||
- [BUGFIX] Abort when encountering unexpected HTTP/3 frames.
|
||||
- [BUGFIX] Acknowledge (QPACK) HTTP/3 trailers correctly.
|
||||
- [DEBUG] Turn on debug message for next advisory tick.
|
||||
|
||||
2019-11-20
|
||||
- 2.6.6
|
||||
- [BUGFIX] Using HTTP/3 to HTTP/1.x converter.
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 6
|
||||
#define LSQUIC_PATCH_VERSION 6
|
||||
#define LSQUIC_PATCH_VERSION 7
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
@ -369,6 +369,9 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
|
|||
/** Allow migration by default */
|
||||
#define LSQUIC_DF_ALLOW_MIGRATION 1
|
||||
|
||||
/** Use QL loss bits by default */
|
||||
#define LSQUIC_DF_QL_BITS 1
|
||||
|
||||
/* 1: Cubic; 2: BBR */
|
||||
#define LSQUIC_DF_CC_ALGO 2
|
||||
|
||||
|
@ -736,6 +739,13 @@ struct lsquic_engine_settings {
|
|||
* 2: BBR
|
||||
*/
|
||||
unsigned es_cc_algo;
|
||||
|
||||
/**
|
||||
* Use QL loss bits.
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_QL_BITS
|
||||
*/
|
||||
int es_ql_bits;
|
||||
};
|
||||
|
||||
/* Initialize `settings' to default values */
|
||||
|
|
|
@ -243,6 +243,7 @@ struct enc_sess_iquic
|
|||
ESI_CACHED_INFO = 1 << 9,
|
||||
ESI_1RTT_ACKED = 1 << 10,
|
||||
ESI_WANT_TICKET = 1 << 11,
|
||||
ESI_QL_BITS = 1 << 12,
|
||||
} esi_flags;
|
||||
enum evp_aead_direction_t
|
||||
esi_dir[2]; /* client, server */
|
||||
|
@ -333,7 +334,10 @@ apply_hp (struct enc_sess_iquic *enc_sess,
|
|||
hp->hp_gen_mask(enc_sess, hp, cliser, dst + packno_off + 4, mask);
|
||||
LSQ_DEBUG("apply header protection using mask %s",
|
||||
HEXSTR(mask, 5, mask_str));
|
||||
dst[0] ^= (0xF | (((dst[0] & 0x80) == 0) << 4)) & mask[0];
|
||||
if (enc_sess->esi_flags & ESI_QL_BITS)
|
||||
dst[0] ^= (0x7 | ((dst[0] >> 7) << 3)) & mask[0];
|
||||
else
|
||||
dst[0] ^= (0xF | (((dst[0] & 0x80) == 0) << 4)) & mask[0];
|
||||
switch (packno_len)
|
||||
{
|
||||
case 4:
|
||||
|
@ -391,7 +395,10 @@ strip_hp (struct enc_sess_iquic *enc_sess,
|
|||
hp->hp_gen_mask(enc_sess, hp, cliser, iv, mask);
|
||||
LSQ_DEBUG("strip header protection using mask %s",
|
||||
HEXSTR(mask, 5, mask_str));
|
||||
dst[0] ^= (0xF | (((dst[0] & 0x80) == 0) << 4)) & mask[0];
|
||||
if (enc_sess->esi_flags & ESI_QL_BITS)
|
||||
dst[0] ^= (0x7 | ((dst[0] >> 7) << 3)) & mask[0];
|
||||
else
|
||||
dst[0] ^= (0xF | (((dst[0] & 0x80) == 0) << 4)) & mask[0];
|
||||
packno = 0;
|
||||
shift = 0;
|
||||
*packno_len = 1 + (dst[0] & 3);
|
||||
|
@ -539,6 +546,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
|||
- !!(params.tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6));
|
||||
if (!settings->es_allow_migration)
|
||||
params.tp_disable_active_migration = 1;
|
||||
if (settings->es_ql_bits)
|
||||
params.tp_flags |= TRAPA_QL_BITS;
|
||||
|
||||
len = lsquic_tp_encode(¶ms, buf, bufsz);
|
||||
if (len >= 0)
|
||||
|
@ -1467,6 +1476,13 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
|||
}
|
||||
}
|
||||
|
||||
if ((trans_params->tp_flags & TRAPA_QL_BITS)
|
||||
&& enc_sess->esi_enpub->enp_settings.es_ql_bits)
|
||||
{
|
||||
LSQ_DEBUG("enable QL loss bits");
|
||||
enc_sess->esi_flags |= ESI_QL_BITS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1978,7 +1994,15 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (dst[0] & (0x0C << (packet_in->pi_header_type == HETY_NOT_SET)))
|
||||
if (enc_sess->esi_flags & ESI_QL_BITS)
|
||||
{
|
||||
packet_in->pi_flags |= PI_LOG_QL_BITS;
|
||||
if (dst[0] & 0x10)
|
||||
packet_in->pi_flags |= PI_SQUARE_BIT;
|
||||
if (dst[0] & 0x08)
|
||||
packet_in->pi_flags |= PI_LOSS_BIT;
|
||||
}
|
||||
else if (dst[0] & (0x0C << (packet_in->pi_header_type == HETY_NOT_SET)))
|
||||
{
|
||||
LSQ_DEBUG("reserved bits are not set to zero");
|
||||
dec_packin = DECPI_VIOLATION;
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
#include "lsquic_logger.h"
|
||||
|
||||
#ifndef LSQUIC_DEBUG_NEXT_ADV_TICK
|
||||
#define LSQUIC_DEBUG_NEXT_ADV_TICK 0
|
||||
#define LSQUIC_DEBUG_NEXT_ADV_TICK 1
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
@ -322,6 +322,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
|
|||
settings->es_qpack_enc_max_size = LSQUIC_DF_QPACK_ENC_MAX_SIZE;
|
||||
settings->es_qpack_enc_max_blocked = LSQUIC_DF_QPACK_ENC_MAX_BLOCKED;
|
||||
settings->es_allow_migration = LSQUIC_DF_ALLOW_MIGRATION;
|
||||
settings->es_ql_bits = LSQUIC_DF_QL_BITS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,13 +66,24 @@ lsquic_ev_log_packet_in (const lsquic_cid_t *cid,
|
|||
(unsigned) (packet_in->pi_data_sz + GQUIC_PACKET_HASH_SZ));
|
||||
break;
|
||||
default:
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
(unsigned) (packet_in->pi_data_sz + IQUIC_TAG_LEN),
|
||||
lsquic_packet_in_ecn(packet_in),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_in_spin_bit(packet_in), packet_in->pi_path_id);
|
||||
if (packet_in->pi_flags & PI_LOG_QL_BITS)
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu; Q: %d; L: %d",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
(unsigned) (packet_in->pi_data_sz + IQUIC_TAG_LEN),
|
||||
lsquic_packet_in_ecn(packet_in),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_in_spin_bit(packet_in), packet_in->pi_path_id,
|
||||
((packet_in->pi_flags & PI_SQUARE_BIT) > 0),
|
||||
((packet_in->pi_flags & PI_LOSS_BIT) > 0));
|
||||
else
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
(unsigned) (packet_in->pi_data_sz + IQUIC_TAG_LEN),
|
||||
lsquic_packet_in_ecn(packet_in),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_in_spin_bit(packet_in), packet_in->pi_path_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +231,27 @@ lsquic_ev_log_packet_sent (const lsquic_cid_t *cid,
|
|||
*/
|
||||
lsquic_frame_types_to_str(frames, sizeof(frames),
|
||||
packet_out->po_frame_types));
|
||||
else if (packet_out->po_lflags & POL_LOG_QL_BITS)
|
||||
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
|
||||
"types: %s, ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u; "
|
||||
"Q: %u; L: %u",
|
||||
packet_out->po_packno, lsquic_hety2str[packet_out->po_header_type],
|
||||
lsquic_enclev2str[ lsquic_packet_out_enc_level(packet_out) ],
|
||||
packet_out->po_enc_data_sz,
|
||||
/* Frame types is a list of different frames types contained
|
||||
* in the packet, no more. Count and order of frames is not
|
||||
* printed.
|
||||
*/
|
||||
lsquic_frame_types_to_str(frames, sizeof(frames),
|
||||
packet_out->po_frame_types),
|
||||
lsquic_packet_out_ecn(packet_out),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_out_spin_bit(packet_out),
|
||||
lsquic_packet_out_kp(packet_out),
|
||||
packet_out->po_path->np_path_id,
|
||||
(unsigned) packet_out->po_flags,
|
||||
lsquic_packet_out_square_bit(packet_out),
|
||||
lsquic_packet_out_loss_bit(packet_out));
|
||||
else
|
||||
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
|
||||
"types: %s, ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u",
|
||||
|
|
|
@ -2690,6 +2690,13 @@ handshake_ok (struct lsquic_conn *lconn)
|
|||
LSQ_DEBUG("peer transport parameters: %s",
|
||||
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
|
||||
|
||||
if ((params->tp_flags & TRAPA_QL_BITS)
|
||||
&& conn->ifc_settings->es_ql_bits)
|
||||
{
|
||||
LSQ_DEBUG("turn on QL loss bits");
|
||||
lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl);
|
||||
}
|
||||
|
||||
if (params->tp_init_max_streams_bidi > (1ull << 60)
|
||||
|| params->tp_init_max_streams_uni > (1ull << 60))
|
||||
{
|
||||
|
|
|
@ -83,7 +83,11 @@ typedef struct lsquic_packet_in
|
|||
#define PIBIT_BITS_SHIFT 12
|
||||
PI_BITS_BIT_0 = (1 <<12),
|
||||
PI_BITS_BIT_1 = (1 <<13),
|
||||
} pi_flags:16;
|
||||
/* Square bit and loss bit flags are used for logging */
|
||||
PI_LOG_QL_BITS = (1 <<14),
|
||||
PI_SQUARE_BIT = (1 <<15),
|
||||
PI_LOSS_BIT = (1 <<16),
|
||||
} pi_flags;
|
||||
/* pi_token and pi_token_size are set in Initial and Retry packets */
|
||||
unsigned short pi_token_size; /* Size of the token */
|
||||
unsigned char pi_token; /* Offset to token */
|
||||
|
|
|
@ -143,7 +143,10 @@ typedef struct lsquic_packet_out
|
|||
#define POECN_SHIFT 4
|
||||
POL_ECNBIT_0 = 1 << 4,
|
||||
POL_ECNBIT_1 = 1 << 5,
|
||||
} po_lflags:8;
|
||||
POL_LOG_QL_BITS = 1 << 6,
|
||||
POL_SQUARE_BIT = 1 << 7,
|
||||
POL_LOSS_BIT = 1 << 8,
|
||||
} po_lflags:16;
|
||||
unsigned char *po_data;
|
||||
|
||||
/* A lot of packets contain data belonging to only one stream. Thus,
|
||||
|
@ -199,6 +202,8 @@ typedef struct lsquic_packet_out
|
|||
} while (0)
|
||||
|
||||
#define lsquic_packet_out_spin_bit(p) (((p)->po_flags & PO_SPIN_BIT) > 0)
|
||||
#define lsquic_packet_out_square_bit(p) (((p)->po_lflags & POL_SQUARE_BIT) > 0)
|
||||
#define lsquic_packet_out_loss_bit(p) (((p)->po_lflags & POL_LOSS_BIT) > 0)
|
||||
|
||||
#define lsquic_packet_out_set_spin_bit(p, b) do { \
|
||||
(p)->po_flags &= ~PO_SPIN_BIT; \
|
||||
|
|
|
@ -260,6 +260,8 @@ gen_short_pkt_header (const struct lsquic_conn *lconn,
|
|||
|
||||
buf[0] = 0x40
|
||||
| (lsquic_packet_out_spin_bit(packet_out) << 5)
|
||||
| (lsquic_packet_out_square_bit(packet_out) << 4)
|
||||
| (lsquic_packet_out_loss_bit(packet_out) << 3)
|
||||
| (lsquic_packet_out_key_phase(packet_out) << 2)
|
||||
| packno_bits
|
||||
;
|
||||
|
|
|
@ -384,10 +384,12 @@ qdh_supply_hset_to_stream (struct qpack_dec_hdl *qdh,
|
|||
struct uncompressed_headers *uh = NULL;
|
||||
const struct lsqpack_header *header;
|
||||
enum lsquic_header_status st;
|
||||
int push_promise;
|
||||
unsigned i;
|
||||
void *hset;
|
||||
|
||||
hset = hset_if->hsi_create_header_set(qdh->qdh_hsi_ctx, 0);
|
||||
push_promise = lsquic_stream_header_is_pp(stream);
|
||||
hset = hset_if->hsi_create_header_set(qdh->qdh_hsi_ctx, push_promise);
|
||||
if (!hset)
|
||||
{
|
||||
LSQ_INFO("call to hsi_create_header_set failed");
|
||||
|
@ -440,6 +442,21 @@ qdh_supply_hset_to_stream (struct qpack_dec_hdl *qdh,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
qdh_process_qlist (struct qpack_dec_hdl *qdh,
|
||||
struct lsquic_stream *stream, struct lsqpack_header_list *qlist)
|
||||
{
|
||||
if (!lsquic_stream_header_is_trailer(stream))
|
||||
return qdh_supply_hset_to_stream(qdh, stream, qlist);
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("discard trailer header set");
|
||||
lsqpack_dec_destroy_header_list(qlist);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static enum lsqpack_read_header_status
|
||||
qdh_header_read_results (struct qpack_dec_hdl *qdh,
|
||||
struct lsquic_stream *stream, enum lsqpack_read_header_status rhs,
|
||||
|
@ -452,7 +469,7 @@ qdh_header_read_results (struct qpack_dec_hdl *qdh,
|
|||
{
|
||||
if (qlist)
|
||||
{
|
||||
if (0 != qdh_supply_hset_to_stream(qdh, stream, qlist))
|
||||
if (0 != qdh_process_qlist(qdh, stream, qlist))
|
||||
return LQRHS_ERROR;
|
||||
if (qdh->qdh_dec_sm_out)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ struct qpack_dec_hdl
|
|||
struct lsquic_conn *qdh_conn;
|
||||
enum {
|
||||
QDH_INITIALIZED = 1 << 0,
|
||||
QDH_PUSH_PROMISE = 1 << 1,
|
||||
} qdh_flags;
|
||||
struct lsqpack_dec qdh_decoder;
|
||||
struct lsquic_stream *qdh_enc_sm_in;
|
||||
|
|
|
@ -765,6 +765,8 @@ send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl,
|
|||
assert(ctl->sc_n_in_flight_all);
|
||||
packet_sz = packet_out_sent_sz(packet_out);
|
||||
|
||||
++ctl->sc_loss_count;
|
||||
|
||||
if (packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
|
||||
{
|
||||
ctl->sc_flags |= SC_LOST_ACK_INIT << lsquic_packet_out_pns(packet_out);
|
||||
|
@ -1610,6 +1612,25 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl, size_t size)
|
|||
send_ctl_maybe_zero_pad(ctl, packet_out, size ? size : 1200);
|
||||
}
|
||||
|
||||
if (ctl->sc_flags & SC_QL_BITS)
|
||||
{
|
||||
packet_out->po_lflags |= POL_LOG_QL_BITS;
|
||||
if (ctl->sc_loss_count)
|
||||
{
|
||||
--ctl->sc_loss_count;
|
||||
packet_out->po_lflags |= POL_LOSS_BIT;
|
||||
}
|
||||
else
|
||||
packet_out->po_lflags &= ~POL_LOSS_BIT;
|
||||
if (packet_out->po_header_type == HETY_NOT_SET)
|
||||
{
|
||||
if (ctl->sc_square_count++ & 128)
|
||||
packet_out->po_lflags |= POL_SQUARE_BIT;
|
||||
else
|
||||
packet_out->po_lflags &= ~POL_SQUARE_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
|
@ -1625,6 +1646,8 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
|
|||
#if LSQUIC_SEND_STATS
|
||||
++ctl->sc_stats.n_delayed;
|
||||
#endif
|
||||
if (packet_out->po_lflags & POL_LOSS_BIT)
|
||||
++ctl->sc_loss_count;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ enum send_ctl_flags {
|
|||
SC_1RTT_ACKED = 1 << 11,
|
||||
SC_APP_LIMITED = 1 << 12,
|
||||
SC_ECN = 1 << 13,
|
||||
SC_QL_BITS = 1 << 14,
|
||||
};
|
||||
|
||||
typedef struct lsquic_send_ctl {
|
||||
|
@ -124,6 +125,8 @@ typedef struct lsquic_send_ctl {
|
|||
unsigned sc_retry_count;
|
||||
unsigned sc_rt_count; /* Count round trips */
|
||||
lsquic_packno_t sc_cur_rt_end;
|
||||
unsigned sc_loss_count; /* Used to set loss bit */
|
||||
unsigned sc_square_count;/* Used to set square bit */
|
||||
} lsquic_send_ctl_t;
|
||||
|
||||
void
|
||||
|
@ -357,4 +360,8 @@ void
|
|||
lsquic_send_ctl_maybe_app_limited (struct lsquic_send_ctl *,
|
||||
const struct network_path *);
|
||||
|
||||
#define lsquic_send_ctl_do_ql_bits(ctl) do { \
|
||||
(ctl)->sc_flags |= SC_QL_BITS; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3726,8 +3726,9 @@ lsquic_stream_push_info (const lsquic_stream_t *stream,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_stream_uh_in (lsquic_stream_t *stream, struct uncompressed_headers *uh)
|
||||
static int
|
||||
stream_uh_in_gquic (struct lsquic_stream *stream,
|
||||
struct uncompressed_headers *uh)
|
||||
{
|
||||
if ((stream->sm_bflags & SMBF_USE_HEADERS)
|
||||
&& !(stream->stream_flags & STREAM_HAVE_UH))
|
||||
|
@ -3764,6 +3765,68 @@ lsquic_stream_uh_in (lsquic_stream_t *stream, struct uncompressed_headers *uh)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
stream_uh_in_ietf (struct lsquic_stream *stream,
|
||||
struct uncompressed_headers *uh)
|
||||
{
|
||||
int push_promise;
|
||||
|
||||
push_promise = lsquic_stream_header_is_pp(stream);
|
||||
if (!(stream->stream_flags & STREAM_HAVE_UH) && !push_promise)
|
||||
{
|
||||
SM_HISTORY_APPEND(stream, SHE_HEADERS_IN);
|
||||
LSQ_DEBUG("received uncompressed headers");
|
||||
stream->stream_flags |= STREAM_HAVE_UH;
|
||||
if (uh->uh_flags & UH_FIN)
|
||||
{
|
||||
/* IETF QUIC only sets UH_FIN for a pushed stream on the server to
|
||||
* mark request as done:
|
||||
*/
|
||||
if (stream->sm_bflags & SMBF_IETF)
|
||||
assert((stream->sm_bflags & SMBF_SERVER)
|
||||
&& lsquic_stream_is_pushed(stream));
|
||||
stream->stream_flags |= STREAM_FIN_RECVD|STREAM_HEAD_IN_FIN;
|
||||
}
|
||||
stream->uh = uh;
|
||||
if (uh->uh_oth_stream_id == 0)
|
||||
{
|
||||
if (uh->uh_weight)
|
||||
lsquic_stream_set_priority_internal(stream, uh->uh_weight);
|
||||
}
|
||||
else
|
||||
LSQ_NOTICE("don't know how to depend on stream %"PRIu64,
|
||||
uh->uh_oth_stream_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Trailer should never make here, as we discard it in qdh */
|
||||
LSQ_DEBUG("discard %s header set",
|
||||
push_promise ? "push promise" : "trailer");
|
||||
if (uh->uh_hset)
|
||||
stream->conn_pub->enpub->enp_hsi_if
|
||||
->hsi_discard_header_set(uh->uh_hset);
|
||||
free(uh);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_stream_uh_in (lsquic_stream_t *stream, struct uncompressed_headers *uh)
|
||||
{
|
||||
if (stream->sm_bflags & SMBF_USE_HEADERS)
|
||||
{
|
||||
if (stream->sm_bflags & SMBF_IETF)
|
||||
return stream_uh_in_ietf(stream, uh);
|
||||
else
|
||||
return stream_uh_in_gquic(stream, uh);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
lsquic_stream_priority (const lsquic_stream_t *stream)
|
||||
{
|
||||
|
@ -3961,7 +4024,8 @@ lsquic_stream_set_stream_if (struct lsquic_stream *stream,
|
|||
|
||||
|
||||
static int
|
||||
update_type_hist_and_check (struct hq_filter *filter)
|
||||
update_type_hist_and_check (const struct lsquic_stream *stream,
|
||||
struct hq_filter *filter)
|
||||
{
|
||||
/* 3-bit codes: */
|
||||
enum {
|
||||
|
@ -3988,6 +4052,20 @@ update_type_hist_and_check (struct hq_filter *filter)
|
|||
case HQFT_DATA:
|
||||
code = CODE_DATA;
|
||||
break;
|
||||
case HQFT_PUSH_PROMISE:
|
||||
case HQFT_DUPLICATE_PUSH:
|
||||
/* [draft-ietf-quic-http-24], Section 7 */
|
||||
if ((stream->id & SIT_MASK) == SIT_BIDI_CLIENT
|
||||
&& !(stream->sm_bflags & SMBF_SERVER))
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
case HQFT_CANCEL_PUSH:
|
||||
case HQFT_SETTINGS:
|
||||
case HQFT_GOAWAY:
|
||||
case HQFT_MAX_PUSH_ID:
|
||||
/* [draft-ietf-quic-http-24], Section 7 */
|
||||
return -1;
|
||||
default:
|
||||
/* Ignore unknown frames */
|
||||
return 0;
|
||||
|
@ -4021,6 +4099,21 @@ update_type_hist_and_check (struct hq_filter *filter)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_stream_header_is_pp (const struct lsquic_stream *stream)
|
||||
{
|
||||
return stream->sm_hq_filter.hqfi_type == HQFT_PUSH_PROMISE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_stream_header_is_trailer (const struct lsquic_stream *stream)
|
||||
{
|
||||
return (stream->stream_flags & STREAM_HAVE_UH)
|
||||
&& stream->sm_hq_filter.hqfi_type == HQFT_HEADERS;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
||||
{
|
||||
|
@ -4037,11 +4130,11 @@ hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
|||
switch (filter->hqfi_state)
|
||||
{
|
||||
case HQFI_STATE_FRAME_HEADER_BEGIN:
|
||||
filter->hqfi_vint_state.vr2s_state = 0;
|
||||
filter->hqfi_vint2_state.vr2s_state = 0;
|
||||
filter->hqfi_state = HQFI_STATE_FRAME_HEADER_CONTINUE;
|
||||
/* fall-through */
|
||||
case HQFI_STATE_FRAME_HEADER_CONTINUE:
|
||||
s = lsquic_varint_read_two(&p, end, &filter->hqfi_vint_state);
|
||||
s = lsquic_varint_read_two(&p, end, &filter->hqfi_vint2_state);
|
||||
if (s < 0)
|
||||
break;
|
||||
filter->hqfi_flags |= HQFI_FLAG_BEGIN;
|
||||
|
@ -4049,7 +4142,7 @@ hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
|||
LSQ_DEBUG("HQ frame type 0x%"PRIX64" at offset %"PRIu64", size %"PRIu64,
|
||||
filter->hqfi_type, stream->read_offset + (unsigned) (p - buf),
|
||||
filter->hqfi_left);
|
||||
if (0 != update_type_hist_and_check(filter))
|
||||
if (0 != update_type_hist_and_check(stream, filter))
|
||||
{
|
||||
lconn = stream->conn_pub->lconn;
|
||||
filter->hqfi_flags |= HQFI_FLAG_ERROR;
|
||||
|
@ -4060,37 +4153,23 @@ hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
|||
stream->id);
|
||||
goto end;
|
||||
}
|
||||
if (filter->hqfi_type == HQFT_HEADERS)
|
||||
{
|
||||
if (0 == (filter->hqfi_flags & HQFI_FLAG_GOT_HEADERS))
|
||||
filter->hqfi_flags |= HQFI_FLAG_GOT_HEADERS;
|
||||
else
|
||||
{
|
||||
filter->hqfi_type = (1ull << 62) - 1;
|
||||
LSQ_DEBUG("Ignoring HEADERS frame");
|
||||
}
|
||||
}
|
||||
if (filter->hqfi_left > 0)
|
||||
{
|
||||
if (filter->hqfi_type == HQFT_DATA)
|
||||
goto end;
|
||||
else if (filter->hqfi_type == HQFT_PUSH_PROMISE)
|
||||
{
|
||||
lconn = stream->conn_pub->lconn;
|
||||
if (stream->sm_bflags & SMBF_SERVER)
|
||||
{
|
||||
lconn = stream->conn_pub->lconn;
|
||||
lconn->cn_if->ci_abort_error(lconn, 1,
|
||||
HEC_FRAME_UNEXPECTED, "Received PUSH_PROMISE frame "
|
||||
"on stream %"PRIu64" (clients are not supposed to "
|
||||
"send those)", stream->id);
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
/* Our client implementation does not support server
|
||||
* push.
|
||||
*/
|
||||
lconn->cn_if->ci_abort_error(lconn, 1,
|
||||
HEC_FRAME_UNEXPECTED,
|
||||
"Received PUSH_PROMISE frame (not supported)"
|
||||
"on stream %"PRIu64, stream->id);
|
||||
goto end;
|
||||
filter->hqfi_state = HQFI_STATE_PUSH_ID_BEGIN;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4115,6 +4194,18 @@ hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case HQFI_STATE_PUSH_ID_BEGIN:
|
||||
filter->hqfi_vint1_state.pos = 0;
|
||||
filter->hqfi_state = HQFI_STATE_PUSH_ID_CONTINUE;
|
||||
/* Fall-through */
|
||||
case HQFI_STATE_PUSH_ID_CONTINUE:
|
||||
prev = p;
|
||||
s = lsquic_varint_read_nb(&p, end, &filter->hqfi_vint1_state);
|
||||
filter->hqfi_left -= p - prev;
|
||||
if (s == 0)
|
||||
filter->hqfi_state = HQFI_STATE_READING_PAYLOAD;
|
||||
/* A bit of a white lie here */
|
||||
break;
|
||||
case HQFI_STATE_READING_PAYLOAD:
|
||||
if (filter->hqfi_type == HQFT_DATA)
|
||||
goto end;
|
||||
|
@ -4124,6 +4215,7 @@ hq_read (void *ctx, const unsigned char *buf, size_t sz, int fin)
|
|||
switch (filter->hqfi_type)
|
||||
{
|
||||
case HQFT_HEADERS:
|
||||
case HQFT_PUSH_PROMISE:
|
||||
prev = p;
|
||||
if (filter->hqfi_flags & HQFI_FLAG_BEGIN)
|
||||
{
|
||||
|
|
|
@ -101,12 +101,14 @@ struct stream_hq_frame
|
|||
|
||||
struct hq_filter
|
||||
{
|
||||
struct varint_read2_state hqfi_vint_state;
|
||||
struct varint_read2_state hqfi_vint2_state;
|
||||
/* No need to copy the values: use it directly */
|
||||
#define hqfi_left hqfi_vint_state.vr2s_two
|
||||
#define hqfi_type hqfi_vint_state.vr2s_one
|
||||
#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_GOT_HEADERS = 1 << 0,
|
||||
HQFI_FLAG_UNUSED_0 = 1 << 0,
|
||||
HQFI_FLAG_ERROR = 1 << 1,
|
||||
HQFI_FLAG_BEGIN = 1 << 2,
|
||||
HQFI_FLAG_BLOCKED = 1 << 3,
|
||||
|
@ -115,6 +117,8 @@ struct hq_filter
|
|||
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;
|
||||
unsigned char hqfi_hist_idx;
|
||||
#define MAX_HQFI_ENTRIES (sizeof(unsigned) * 8 / 3)
|
||||
|
@ -263,7 +267,7 @@ struct lsquic_stream
|
|||
struct hq_filter sm_hq_filter;
|
||||
|
||||
/* We can safely use sm_hq_filter */
|
||||
#define sm_uni_type_state sm_hq_filter.hqfi_vint_state.vr2s_varint_state
|
||||
#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;
|
||||
|
@ -590,4 +594,10 @@ 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 *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -137,6 +137,9 @@ lsquic_tp_encode (const struct transport_params *params,
|
|||
if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION)
|
||||
need += 4 + 0;
|
||||
|
||||
if (params->tp_flags & TRAPA_QL_BITS)
|
||||
need += 4 + 0;
|
||||
|
||||
if (need > bufsz || need > UINT16_MAX)
|
||||
{
|
||||
errno = ENOBUFS;
|
||||
|
@ -256,6 +259,12 @@ lsquic_tp_encode (const struct transport_params *params,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (params->tp_flags & TRAPA_QL_BITS)
|
||||
{
|
||||
WRITE_UINT_TO_P(TPI_QL_BITS, 16);
|
||||
WRITE_UINT_TO_P(0, 16);
|
||||
}
|
||||
|
||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
if (params->tp_flags & TRAPA_QUANTUM_READY)
|
||||
{
|
||||
|
@ -332,7 +341,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
|
|||
set_of_ids |= 1 << param_id;
|
||||
}
|
||||
else
|
||||
goto unknown;
|
||||
goto gt32;
|
||||
if (NUMERIC_TRANS_PARAMS & (1u << param_id))
|
||||
{
|
||||
switch (len)
|
||||
|
@ -372,7 +381,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
|
|||
}
|
||||
else
|
||||
{
|
||||
switch (param_id)
|
||||
gt32: switch (param_id)
|
||||
{
|
||||
case TPI_DISABLE_ACTIVE_MIGRATION:
|
||||
EXPECT_LEN(0);
|
||||
|
@ -450,8 +459,11 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
|
|||
sizeof(params->tp_preferred_address.ipv6_addr)))
|
||||
params->tp_flags |= TRAPA_PREFADDR_IPv6;
|
||||
break;
|
||||
case TPI_QL_BITS:
|
||||
EXPECT_LEN(0);
|
||||
params->tp_flags |= TRAPA_QL_BITS;
|
||||
break;
|
||||
}
|
||||
unknown:
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
|
@ -536,6 +548,13 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (params->tp_flags & TRAPA_QL_BITS)
|
||||
{
|
||||
nw = snprintf(buf, end - buf, "; QL loss bits");
|
||||
buf += nw;
|
||||
if (buf >= end)
|
||||
return;
|
||||
}
|
||||
|
||||
#undef SEMICOLON
|
||||
#undef WRITE_ONE_PARAM
|
||||
|
|
|
@ -57,6 +57,8 @@ enum trapa_flags
|
|||
#define TPI_QUANTUM_READINESS 3127
|
||||
TRAPA_QUANTUM_READY = 1 << 5, /* Include "Quantum Readiness" TP */
|
||||
#endif
|
||||
#define TPI_QL_BITS 0x1055 /* 1055 is 133t for "loss" */
|
||||
TRAPA_QL_BITS = 1 << 6,
|
||||
};
|
||||
|
||||
struct transport_params
|
||||
|
|
|
@ -1703,6 +1703,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
|
|||
settings->es_cc_algo = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
else if (0 == strncmp(name, "ql_bits", 7))
|
||||
{
|
||||
settings->es_ql_bits = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (0 == strncmp(name, "max_cfcw", 8))
|
||||
|
|
Loading…
Reference in a new issue