Release 2.11.0

- [FEATURE] QUIC and HTTP/3 Internet Draft 27 support.
- [FEATURE] Add experimental delayed ACKs extension.
- Drop support for Internet Draft 24.
- Code cleanup.
This commit is contained in:
Dmitri Tikhonov 2020-02-24 12:02:57 -05:00
parent feca77f50d
commit bc520ef752
38 changed files with 626 additions and 7729 deletions

View file

@ -26,7 +26,6 @@ SET(lsquic_STAT_SRCS
lsquic_frame_reader.c
lsquic_frame_writer.c
lsquic_full_conn.c
lsquic_full_conn_id24.c
lsquic_full_conn_ietf.c
lsquic_global.c
lsquic_handshake.c

View file

@ -31,7 +31,6 @@ liblsquic_a_SOURCES = ls-qpack/lsqpack.c \
lsquic_frame_reader.c \
lsquic_frame_writer.c \
lsquic_full_conn.c \
lsquic_full_conn_id24.c \
lsquic_full_conn_ietf.c \
lsquic_global.c \
lsquic_handshake.c \

View file

@ -40,8 +40,6 @@ const char *const lsquic_alid2str[] =
[AL_RETX_APP] = "RETX_APP",
[AL_PING] = "PING",
[AL_IDLE] = "IDLE",
[AL_ACK_INIT] = "ACK_INIT",
[AL_ACK_HSK] = "ACK_HSK",
[AL_ACK_APP] = "ACK_APP",
[AL_RET_CIDS] = "RET_CIDS",
[AL_CID_THROT] = "CID_THROT",

View file

@ -27,10 +27,7 @@ enum alarm_id {
AL_RETX_APP = AL_RETX_INIT + PNS_APP,
AL_PING,
AL_IDLE,
/* TODO: remove AL_ACK_INIT and AL_ACK_HSK when LSQVER_ID24 is removed */
AL_ACK_INIT,
AL_ACK_HSK = AL_ACK_INIT + PNS_HSK,
AL_ACK_APP = AL_ACK_INIT + PNS_APP,
AL_ACK_APP,
AL_RET_CIDS,
AL_CID_THROT,
AL_PATH_CHAL,
@ -48,8 +45,6 @@ enum alarm_id_bit {
ALBIT_RETX_HSK = 1 << AL_RETX_HSK,
ALBIT_RETX_APP = 1 << AL_RETX_APP,
ALBIT_ACK_APP = 1 << AL_ACK_APP,
ALBIT_ACK_INIT = 1 << AL_ACK_INIT,
ALBIT_ACK_HSK = 1 << AL_ACK_HSK,
ALBIT_PING = 1 << AL_PING,
ALBIT_IDLE = 1 << AL_IDLE,
ALBIT_RET_CIDS = 1 << AL_RET_CIDS,

View file

@ -328,8 +328,8 @@ struct enc_session_funcs_gquic lsquic_enc_session_gquic_gquic_1;
extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
#define select_esf_common_by_ver(ver) ( \
ver == LSQVER_ID24 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID25 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
&lsquic_enc_session_common_gquic_1 )

View file

@ -71,9 +71,9 @@ static const struct alpn_map {
enum lsquic_version version;
const unsigned char *alpn;
} s_alpns[] = {
{ LSQVER_ID24, (unsigned char *) "\x05h3-24", },
{ LSQVER_ID25, (unsigned char *) "\x05h3-25", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-25", },
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-27", },
};
struct enc_sess_iquic;
@ -546,12 +546,6 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
| (1 << TPI_MAX_PACKET_SIZE)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
;
if (enc_sess->esi_conn->cn_version == LSQVER_ID24)
{
params.tp_active_connection_id_limit = params.tp_active_connection_id_limit
- 1 /* One slot is used by peer's SCID */
- !!(params.tp_set & (1 << TPI_PREFERRED_ADDRESS));
}
if (!settings->es_allow_migration)
params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
if (settings->es_ql_bits)
@ -565,7 +559,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
params.tp_set |= 1 << TPI_MIN_ACK_DELAY;
}
len = lsquic_tp_encode(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
len = (enc_sess->esi_conn->cn_version == LSQVER_ID25 ? lsquic_tp_encode_id25 :
lsquic_tp_encode)(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
if (len >= 0)
LSQ_DEBUG("generated transport parameters buffer of %d bytes", len);
else
@ -1460,7 +1455,8 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
}
LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
if (0 > lsquic_tp_decode(params_buf, bufsz,
if (0 > (enc_sess->esi_conn->cn_version == LSQVER_ID25
? lsquic_tp_decode_id25 : lsquic_tp_decode)(params_buf, bufsz,
!(enc_sess->esi_flags & ESI_SERVER),
trans_params))
{
@ -2674,7 +2670,8 @@ static void
chsk_ietf_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
{
struct enc_sess_iquic *const enc_sess = (struct enc_sess_iquic *) ctx;
LSQ_DEBUG("crypto stream level %u is closed",
if (enc_sess && enc_sess->esi_cryst_if)
LSQ_DEBUG("crypto stream level %u is closed",
(unsigned) enc_sess->esi_cryst_if->csi_enc_level(stream));
}

View file

@ -900,12 +900,7 @@ new_full_conn_server (lsquic_engine_t *engine, lsquic_conn_t *mini_conn,
flags = engine->flags & (ENG_SERVER|ENG_HTTP);
if (mini_conn->cn_flags & LSCONN_IETF)
{
if (mini_conn->cn_version == LSQVER_ID24)
ctor = lsquic_id24_full_conn_server_new;
else
ctor = lsquic_ietf_full_conn_server_new;
}
ctor = lsquic_ietf_full_conn_server_new;
else
ctor = lsquic_gquic_full_conn_server_new;
@ -1562,16 +1557,9 @@ lsquic_engine_connect (lsquic_engine_t *engine, enum lsquic_version version,
else
versions = 1u << version;
if (versions & LSQUIC_IETF_VERSIONS)
{
if (version == LSQVER_ID24)
conn = lsquic_id24_full_conn_client_new(&engine->pub, versions,
flags, hostname, max_packet_size,
is_ipv4, zero_rtt, zero_rtt_len, token, token_sz);
else
conn = lsquic_ietf_full_conn_client_new(&engine->pub, versions,
flags, hostname, max_packet_size,
is_ipv4, zero_rtt, zero_rtt_len, token, token_sz);
}
conn = lsquic_ietf_full_conn_client_new(&engine->pub, versions,
flags, hostname, max_packet_size,
is_ipv4, zero_rtt, zero_rtt_len, token, token_sz);
else
conn = lsquic_gquic_full_conn_client_new(&engine->pub, versions,
flags, hostname, max_packet_size, is_ipv4,

View file

@ -21,14 +21,6 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *,
const unsigned char *zero_rtt, size_t,
const unsigned char *token, size_t);
struct lsquic_conn *
lsquic_id24_full_conn_client_new (struct lsquic_engine_public *,
unsigned versions,
unsigned flags /* Only FC_SERVER and FC_HTTP */,
const char *hostname, unsigned short max_packet_size, int is_ipv4,
const unsigned char *zero_rtt, size_t,
const unsigned char *token, size_t);
typedef struct lsquic_conn *
(*server_conn_ctor_f) (struct lsquic_engine_public *,
unsigned flags /* Only FC_SERVER and FC_HTTP */,
@ -44,11 +36,6 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *,
unsigned flags /* Only FC_SERVER and FC_HTTP */,
struct lsquic_conn *mini_conn);
struct lsquic_conn *
lsquic_id24_full_conn_server_new (struct lsquic_engine_public *,
unsigned flags /* Only FC_SERVER and FC_HTTP */,
struct lsquic_conn *mini_conn);
struct dcid_elem
{
/* This is never both in the hash and on the retirement list */

File diff suppressed because it is too large Load diff

View file

@ -1341,8 +1341,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
assert(mini_conn->cn_flags & LSCONN_HANDSHAKE_DONE);
conn->ifc_conn.cn_flags |= LSCONN_HANDSHAKE_DONE;
if (mini_conn->cn_version > LSQVER_ID24
&& !(imc->imc_flags & IMC_HSK_DONE_SENT))
if (!(imc->imc_flags & IMC_HSK_DONE_SENT))
{
LSQ_DEBUG("HANDSHAKE_DONE not yet sent, will process CRYPTO frames");
conn->ifc_flags |= IFC_PROC_CRYPTO;
@ -1559,8 +1558,6 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
conn->ifc_n_slack_all = 0;
lsquic_alarmset_unset(&conn->ifc_alset, AL_ACK_APP);
}
else
assert(!lsquic_alarmset_is_set(&conn->ifc_alset, AL_ACK_INIT + pns));
lsquic_send_ctl_sanity_check(&conn->ifc_send_ctl);
LSQ_DEBUG("%s ACK state reset", lsquic_pns2str[pns]);
@ -3010,8 +3007,7 @@ handshake_ok (struct lsquic_conn *lconn)
conn->ifc_ping_period = 0;
LSQ_DEBUG("PING period is set to %"PRIu64" usec", conn->ifc_ping_period);
if (conn->ifc_conn.cn_version > LSQVER_ID24
&& conn->ifc_settings->es_delayed_acks
if (conn->ifc_settings->es_delayed_acks
&& (params->tp_set & (1 << TPI_MIN_ACK_DELAY)))
{
LSQ_DEBUG("delayed ACKs enabled");
@ -3265,11 +3261,11 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
return -1;
}
/* Generate header block. Using it, we will search for a duplicate push
* promise. If not found, it will be copied to a new push_promise object.
/* Generate header block in cheap 4K memory. It it will be copied to
* a new push_promise object.
*/
p = header_block_buf;
end = header_block_buf + 0x1000 - 1; /* Save one byte for key type */
end = header_block_buf + 0x1000;
pseudo_headers[0].name. iov_base = ":method";
pseudo_headers[0].name. iov_len = 7;
pseudo_headers[0].value.iov_base = "GET";
@ -3326,18 +3322,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
}
LSQ_DEBUG("generated push promise header block of %ld bytes",
(long) (p - header_block_buf));
*p++ = PPKT_CONTENT;
el = lsquic_hash_find(conn->ifc_pub.u.ietf.promises,
header_block_buf, p - header_block_buf);
if (el)
{
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
promise = lsquic_hashelem_getdata(el);
LSQ_DEBUG("found push promise %"PRIu64", will issue a duplicate",
promise->pp_id);
return lsquic_stream_duplicate_push(dep_stream, promise->pp_id);
}
own_hset = !hset;
if (!hset)
@ -3358,6 +3342,7 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
if (!hset)
{
LSQ_INFO("header set ctor failure");
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
return -1;
}
for (i = 0; i < n_header_sets; ++i)
@ -3439,13 +3424,12 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
memset(promise, 0, sizeof(*promise));
promise->pp_refcnt = 1; /* This function itself keeps a reference */
memcpy(promise->pp_content_buf, header_block_buf, p - header_block_buf);
promise->pp_content_len = p - header_block_buf - 1;
promise->pp_content_len = p - header_block_buf;
promise->pp_id = conn->ifc_u.ser.ifser_next_push_id++;
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
promise->pp_u_id.buf[8] = PPKT_ID;
el = lsquic_hash_insert(conn->ifc_pub.u.ietf.promises,
promise->pp_u_id.buf, sizeof(promise->pp_u_id.buf), promise,
&promise->pp_id, sizeof(promise->pp_id), promise,
&promise->pp_hash_id);
if (!el)
{
@ -3457,19 +3441,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
free(uh);
return -1;
}
el = lsquic_hash_insert(conn->ifc_pub.u.ietf.promises,
promise->pp_content_buf, promise->pp_content_len + 1, promise,
&promise->pp_hash_content);
if (!el)
{
LSQ_WARN("cannot insert push promise (content)");
undo_stream_creation(conn, pushed_stream);
if (own_hset)
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
lsquic_pp_put(promise, conn->ifc_pub.u.ietf.promises);
free(uh);
return -1;
}
if (0 != lsquic_stream_push_promise(dep_stream, promise))
{

View file

@ -1,12 +1,12 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_hq.h -- HTTP over QUIC (HQ) types
* lsquic_hq.h -- HTTP/3 (originally "HTTP over QUIC" or HQ) types
*/
#ifndef LSQUIC_HQ_H
#define LSQUIC_HQ_H 1
/* [draft-ietf-quic-http-15] Section 4 */
/* [draft-ietf-quic-http-27] Section 11.2.1 */
enum hq_frame_type
{
HQFT_DATA = 0,
@ -16,7 +16,6 @@ enum hq_frame_type
HQFT_PUSH_PROMISE = 5,
HQFT_GOAWAY = 7,
HQFT_MAX_PUSH_ID = 0xD,
HQFT_DUPLICATE_PUSH = 0xE,
/* This frame is made up and its type is never written to stream.
* Nevertheless, just to be on the safe side, give it a value as
* described in [draft-ietf-quic-http-20] Section 4.2.10.

View file

@ -1689,13 +1689,10 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
}
else if (conn->imc_flags & IMC_HSK_OK)
{
if (conn->imc_conn.cn_version > LSQVER_ID24)
{
if (lconn->cn_esf.i->esfi_in_init(lconn->cn_enc_session))
LSQ_DEBUG("still in init, defer HANDSHAKE_DONE");
else if (0 != imico_generate_handshake_done(conn))
goto close_on_error;
}
if (lconn->cn_esf.i->esfi_in_init(lconn->cn_enc_session))
LSQ_DEBUG("still in init, defer HANDSHAKE_DONE");
else if (0 != imico_generate_handshake_done(conn))
goto close_on_error;
tick |= TICK_PROMOTE;
}

View file

@ -316,7 +316,6 @@ struct parse_funcs
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q043;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q046;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q050;
extern const struct parse_funcs lsquic_parse_funcs_ietf_id24;
extern const struct parse_funcs lsquic_parse_funcs_ietf_v1;
#define select_pf_by_ver(ver) ( \
@ -326,8 +325,6 @@ extern const struct parse_funcs lsquic_parse_funcs_ietf_v1;
&lsquic_parse_funcs_gquic_Q046 : \
(1 << (ver)) & ((1 << LSQVER_050)|LSQUIC_EXPERIMENTAL_Q098) ? \
&lsquic_parse_funcs_gquic_Q050 : \
(1 << (ver)) & (1 << LSQVER_ID24) ? \
&lsquic_parse_funcs_ietf_id24 : \
&lsquic_parse_funcs_ietf_v1)
/* This function is gQUIC-version independent */

View file

@ -1117,85 +1117,6 @@ ietf_v1_parse_frame_type (const unsigned char *buf, size_t len)
}
static enum quic_frame_type
ietf_id24_parse_frame_type (const unsigned char *buf, size_t len)
{
/* This one does not have QUIC_FRAME_HANDSHAKE_DONE */
static const enum quic_frame_type byte2type[0x40] =
{
[0x00] = QUIC_FRAME_PADDING,
[0x01] = QUIC_FRAME_PING,
[0x02] = QUIC_FRAME_ACK,
[0x03] = QUIC_FRAME_ACK,
[0x04] = QUIC_FRAME_RST_STREAM,
[0x05] = QUIC_FRAME_STOP_SENDING,
[0x06] = QUIC_FRAME_CRYPTO,
[0x07] = QUIC_FRAME_NEW_TOKEN,
[0x08] = QUIC_FRAME_STREAM,
[0x09] = QUIC_FRAME_STREAM,
[0x0A] = QUIC_FRAME_STREAM,
[0x0B] = QUIC_FRAME_STREAM,
[0x0C] = QUIC_FRAME_STREAM,
[0x0D] = QUIC_FRAME_STREAM,
[0x0E] = QUIC_FRAME_STREAM,
[0x0F] = QUIC_FRAME_STREAM,
[0x10] = QUIC_FRAME_MAX_DATA,
[0x11] = QUIC_FRAME_MAX_STREAM_DATA,
[0x12] = QUIC_FRAME_MAX_STREAMS,
[0x13] = QUIC_FRAME_MAX_STREAMS,
[0x14] = QUIC_FRAME_BLOCKED,
[0x15] = QUIC_FRAME_STREAM_BLOCKED,
[0x16] = QUIC_FRAME_STREAMS_BLOCKED,
[0x17] = QUIC_FRAME_STREAMS_BLOCKED,
[0x18] = QUIC_FRAME_NEW_CONNECTION_ID,
[0x19] = QUIC_FRAME_RETIRE_CONNECTION_ID,
[0x1A] = QUIC_FRAME_PATH_CHALLENGE,
[0x1B] = QUIC_FRAME_PATH_RESPONSE,
[0x1C] = QUIC_FRAME_CONNECTION_CLOSE,
[0x1D] = QUIC_FRAME_CONNECTION_CLOSE,
[0x1E] = QUIC_FRAME_INVALID,
[0x1F] = QUIC_FRAME_INVALID,
[0x20] = QUIC_FRAME_INVALID,
[0x21] = QUIC_FRAME_INVALID,
[0x22] = QUIC_FRAME_INVALID,
[0x23] = QUIC_FRAME_INVALID,
[0x24] = QUIC_FRAME_INVALID,
[0x25] = QUIC_FRAME_INVALID,
[0x26] = QUIC_FRAME_INVALID,
[0x27] = QUIC_FRAME_INVALID,
[0x28] = QUIC_FRAME_INVALID,
[0x29] = QUIC_FRAME_INVALID,
[0x2A] = QUIC_FRAME_INVALID,
[0x2B] = QUIC_FRAME_INVALID,
[0x2C] = QUIC_FRAME_INVALID,
[0x2D] = QUIC_FRAME_INVALID,
[0x2E] = QUIC_FRAME_INVALID,
[0x2F] = QUIC_FRAME_INVALID,
[0x30] = QUIC_FRAME_INVALID,
[0x31] = QUIC_FRAME_INVALID,
[0x32] = QUIC_FRAME_INVALID,
[0x33] = QUIC_FRAME_INVALID,
[0x34] = QUIC_FRAME_INVALID,
[0x35] = QUIC_FRAME_INVALID,
[0x36] = QUIC_FRAME_INVALID,
[0x37] = QUIC_FRAME_INVALID,
[0x38] = QUIC_FRAME_INVALID,
[0x39] = QUIC_FRAME_INVALID,
[0x3A] = QUIC_FRAME_INVALID,
[0x3B] = QUIC_FRAME_INVALID,
[0x3C] = QUIC_FRAME_INVALID,
[0x3D] = QUIC_FRAME_INVALID,
[0x3E] = QUIC_FRAME_INVALID,
[0x3F] = QUIC_FRAME_INVALID,
};
if (len > 1 && buf[0] < 0x40)
return byte2type[buf[0]];
else
return QUIC_FRAME_INVALID;
}
static unsigned
ietf_v1_path_chal_frame_size (void)
{
@ -1770,7 +1691,7 @@ lsquic_ietf_v1_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
const unsigned char *const end = p + length;
lsquic_ver_tag_t tag;
enum header_type header_type;
unsigned dcil, scil, odcil;
unsigned dcil, scil;
int verneg, r;
unsigned char first_byte;
uint64_t payload_len, token_len;
@ -1865,32 +1786,18 @@ lsquic_ietf_v1_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
case HETY_RETRY:
if (p >= end)
return -1;
if (LSQVER_ID24 == lsquic_tag2ver(tag))
{
odcil = *p++;
if (p + odcil > end || odcil > MAX_CID_LEN)
if (p
/* [draft-ietf-quic-transport-25] Section 17.2.5 says that "a
* client MUST discard a Retry packet with a zero-length Retry
* Token field." We might as well do it here.
*/
+ 1
/* Integrity tag length: */
+ 16 > end)
return -1;
packet_in->pi_odcid_len = odcil;
packet_in->pi_odcid = p - packet_in->pi_data;
p += odcil;
packet_in->pi_token = p - packet_in->pi_data;
packet_in->pi_token_size = end - p;
}
else
{
if (p
/* [draft-ietf-quic-transport-25] Section 17.2.5 says that "a
* client MUST discard a Retry packet with a zero-length Retry
* Token field." We might as well do it here.
*/
+ 1
/* Integrity tag length: */
+ 16 > end)
return -1;
packet_in->pi_token = p - packet_in->pi_data;
packet_in->pi_token_size = end - p - 16;
/* Tag validation happens later */
}
packet_in->pi_token = p - packet_in->pi_data;
packet_in->pi_token_size = end - p - 16;
/* Tag validation happens later */
p = end;
length = end - packet_in->pi_data;
state->pps_p = NULL;
@ -2165,22 +2072,6 @@ ietf_v1_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len,
}
static int
ietf_id24_gen_ack_frequency_frame (unsigned char *buf, size_t buf_len,
uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad)
{
return -1;
}
static int
ietf_id24_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len,
uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad)
{
return -1;
}
static unsigned
ietf_v1_ack_frequency_frame_size (uint64_t seqno, uint64_t pack_tol,
uint64_t upd_mad)
@ -2197,93 +2088,6 @@ ietf_v1_handshake_done_frame_size (void)
}
static int
ietf_id24_gen_handshake_done_frame (unsigned char *buf, size_t buf_len)
{
/* ID-24 does not have HANDSHAKE_DONE frame */
return -1;
}
static int
ietf_id24_parse_handshake_done_frame (const unsigned char *buf, size_t buf_len)
{
/* ID-24 does not have HANDSHAKE_DONE frame */
return -1;
}
const struct parse_funcs lsquic_parse_funcs_ietf_id24 =
{
.pf_gen_reg_pkt_header = ietf_v1_gen_reg_pkt_header,
.pf_parse_packet_in_finish = ietf_v1_parse_packet_in_finish,
.pf_gen_stream_frame = ietf_v1_gen_stream_frame,
.pf_calc_stream_frame_header_sz = ietf_v1_calc_stream_frame_header_sz,
.pf_parse_stream_frame = ietf_v1_parse_stream_frame,
.pf_parse_ack_frame = ietf_v1_parse_ack_frame,
.pf_gen_ack_frame = ietf_v1_gen_ack_frame,
.pf_gen_blocked_frame = ietf_v1_gen_blocked_frame,
.pf_parse_blocked_frame = ietf_v1_parse_blocked_frame,
.pf_blocked_frame_size = ietf_v1_blocked_frame_size,
.pf_rst_frame_size = ietf_v1_rst_frame_size,
.pf_gen_rst_frame = ietf_v1_gen_rst_frame,
.pf_parse_rst_frame = ietf_v1_parse_rst_frame,
.pf_connect_close_frame_size = ietf_v1_connect_close_frame_size,
.pf_gen_connect_close_frame = ietf_v1_gen_connect_close_frame,
.pf_parse_connect_close_frame = ietf_v1_parse_connect_close_frame,
.pf_gen_ping_frame = ietf_v1_gen_ping_frame,
.pf_parse_frame_type = ietf_id24_parse_frame_type,
.pf_turn_on_fin = ietf_v1_turn_on_fin,
.pf_packout_size = ietf_v1_packout_size,
.pf_packout_max_header_size = ietf_v1_packout_max_header_size,
.pf_path_chal_frame_size = ietf_v1_path_chal_frame_size,
.pf_parse_path_chal_frame = ietf_v1_parse_path_chal_frame,
.pf_gen_path_chal_frame = ietf_v1_gen_path_chal_frame,
.pf_path_resp_frame_size = ietf_v1_path_resp_frame_size,
.pf_gen_path_resp_frame = ietf_v1_gen_path_resp_frame,
.pf_parse_path_resp_frame = ietf_v1_parse_path_resp_frame,
.pf_calc_packno_bits = ietf_v1_calc_packno_bits,
.pf_packno_bits2len = ietf_v1_packno_bits2len,
.pf_packno_info = ietf_v1_packno_info,
.pf_gen_crypto_frame = ietf_v1_gen_crypto_frame,
.pf_parse_crypto_frame = ietf_v1_parse_crypto_frame,
.pf_calc_crypto_frame_header_sz = ietf_v1_calc_crypto_frame_header_sz,
.pf_parse_max_data = ietf_v1_parse_max_data,
.pf_gen_max_data_frame = ietf_v1_gen_max_data_frame,
.pf_max_data_frame_size = ietf_v1_max_data_frame_size,
.pf_parse_new_conn_id = ietf_v1_parse_new_conn_id,
.pf_gen_stream_blocked_frame = ietf_v1_gen_stream_blocked_frame,
.pf_parse_stream_blocked_frame = ietf_v1_parse_stream_blocked_frame,
.pf_stream_blocked_frame_size = ietf_v1_stream_blocked_frame_size,
.pf_gen_max_stream_data_frame = ietf_v1_gen_max_stream_data_frame,
.pf_parse_max_stream_data_frame = ietf_v1_parse_max_stream_data_frame,
.pf_max_stream_data_frame_size = ietf_v1_max_stream_data_frame_size,
.pf_parse_stop_sending_frame = ietf_v1_parse_stop_sending_frame,
.pf_gen_stop_sending_frame = ietf_v1_gen_stop_sending_frame,
.pf_stop_sending_frame_size = ietf_v1_stop_sending_frame_size,
.pf_parse_new_token_frame = ietf_v1_parse_new_token_frame,
.pf_new_connection_id_frame_size = ietf_v1_new_connection_id_frame_size,
.pf_gen_new_connection_id_frame = ietf_v1_gen_new_connection_id_frame,
.pf_new_token_frame_size = ietf_v1_new_token_frame_size,
.pf_gen_new_token_frame = ietf_v1_gen_new_token_frame,
.pf_parse_retire_cid_frame = ietf_v1_parse_retire_cid_frame,
.pf_gen_retire_cid_frame = ietf_v1_gen_retire_cid_frame,
.pf_retire_cid_frame_size = ietf_v1_retire_cid_frame_size,
.pf_gen_streams_blocked_frame = ietf_v1_gen_streams_blocked_frame,
.pf_parse_streams_blocked_frame = ietf_v1_parse_streams_blocked_frame,
.pf_streams_blocked_frame_size = ietf_v1_streams_blocked_frame_size,
.pf_gen_max_streams_frame = ietf_v1_gen_max_streams_frame,
.pf_parse_max_streams_frame = ietf_v1_parse_max_streams_frame,
.pf_max_streams_frame_size = ietf_v1_max_streams_frame_size,
.pf_gen_handshake_done_frame = ietf_id24_gen_handshake_done_frame,
.pf_parse_handshake_done_frame = ietf_id24_parse_handshake_done_frame,
.pf_handshake_done_frame_size = ietf_v1_handshake_done_frame_size,
.pf_gen_ack_frequency_frame = ietf_id24_gen_ack_frequency_frame,
.pf_parse_ack_frequency_frame = ietf_id24_parse_ack_frequency_frame,
.pf_ack_frequency_frame_size = ietf_v1_ack_frequency_frame_size,
};
const struct parse_funcs lsquic_parse_funcs_ietf_v1 =
{
.pf_gen_reg_pkt_header = ietf_v1_gen_reg_pkt_header,

View file

@ -355,7 +355,7 @@ prq_new_req (struct pr_queue *prq, enum packet_req_type type,
version = lsquic_tag2ver(ver_tag);
}
else /* Got to set it to something sensible... */
version = LSQVER_ID24;
version = LSQVER_ID25;
lsquic_scid_from_packet_in(packet_in, &scid);
return lsquic_prq_new_req(prq, type, flags, version, packet_in->pi_data_sz,

View file

@ -6,12 +6,6 @@ struct lsquic_hash_elem;
struct lsquic_stream;
enum push_promise_key_type {
PPKT_ID,
PPKT_CONTENT,
};
struct push_promise
{
/* A push promise is associated with a single stream, while a stream can
@ -21,19 +15,10 @@ struct push_promise
* frames can be sent out.
*/
SLIST_ENTRY(push_promise) pp_next;
/* Push promises are stored in the same hash and can be searched either
* by ID or by content. To differentiate the two keys, the key type is
* appended at the end PPKT_ID or PPKT_CONTENT.
*/
struct lsquic_hash_elem pp_hash_id,
pp_hash_content;
union {
uint64_t id;
unsigned char buf[9];
} pp_u_id;
#define pp_id pp_u_id.id
/* Push promises are stored a hash and can be searched by ID */
struct lsquic_hash_elem pp_hash_id;
uint64_t pp_id;
struct lsquic_stream *pp_pushed_stream;
/* This does not include the last key-type byte: */
size_t pp_content_len;
/* Number of streams holding a reference to this push promise. When this
* value becomes zero, the push promise is destroyed. See lsquic_pp_put().
@ -64,7 +49,7 @@ struct push_promise
unsigned pp_write_off;
unsigned char pp_encoded_push_id[8];
/* The content buffer is the header block: it does not include Header
* Block Prefix. It is followed by one-byte key type PPKT_CONTENT.
* Block Prefix.
*/
unsigned char pp_content_buf[0];
};
@ -77,9 +62,6 @@ struct push_promise
LSQ_DEBUG("destroy push promise %"PRIu64, (promise_)->pp_id); \
if ((promise_)->pp_hash_id.qhe_flags & QHE_HASHED) \
lsquic_hash_erase(all_promises_, &(promise_)->pp_hash_id); \
if ((promise_)->pp_hash_content.qhe_flags & QHE_HASHED) \
lsquic_hash_erase(all_promises_, \
&(promise_)->pp_hash_content); \
free(promise); \
} \
} \

View file

@ -147,9 +147,6 @@ stream_write_buf (struct lsquic_stream *stream, const void *buf, size_t sz);
static size_t
active_hq_frame_sizes (const struct lsquic_stream *);
static void
on_write_dp_wrapper (struct lsquic_stream *, lsquic_stream_ctx_t *);
static void
on_write_pp_wrapper (struct lsquic_stream *, lsquic_stream_ctx_t *);
@ -1986,8 +1983,6 @@ static void
assert(stream->stream_flags & STREAM_PUSHING);
if (stream_is_pushing_promise(stream))
return on_write_pp_wrapper;
else if (stream->sm_dup_push_off < stream->sm_dup_push_len)
return on_write_dp_wrapper;
else
return stream->stream_if->on_write;
}
@ -4081,7 +4076,6 @@ update_type_hist_and_check (const struct lsquic_stream *stream,
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))
@ -4566,128 +4560,6 @@ lsquic_stream_can_push (const struct lsquic_stream *stream)
}
static size_t
dp_reader_read (void *lsqr_ctx, void *buf, size_t count)
{
struct lsquic_stream *const stream = lsqr_ctx;
unsigned char *dst = buf;
unsigned char *const end = buf + count;
size_t len;
len = MIN((size_t) (stream->sm_dup_push_len - stream->sm_dup_push_off),
(size_t) (end - dst));
memcpy(dst, stream->sm_dup_push_buf + stream->sm_dup_push_off, len);
stream->sm_dup_push_off += len;
if (stream->sm_dup_push_len == stream->sm_dup_push_off)
LSQ_DEBUG("finish writing duplicate push");
return len;
}
static size_t
dp_reader_size (void *lsqr_ctx)
{
struct lsquic_stream *const stream = lsqr_ctx;
return stream->sm_dup_push_len - stream->sm_dup_push_off;
}
static void
init_dp_reader (struct lsquic_stream *stream, struct lsquic_reader *reader)
{
reader->lsqr_read = dp_reader_read;
reader->lsqr_size = dp_reader_size;
reader->lsqr_ctx = stream;
}
static void
on_write_dp_wrapper (struct lsquic_stream *stream, lsquic_stream_ctx_t *h)
{
struct lsquic_reader dp_reader;
ssize_t nw;
int want_write;
assert(stream->sm_dup_push_off < stream->sm_dup_push_len);
init_dp_reader(stream, &dp_reader);
nw = stream_write(stream, &dp_reader);
if (nw > 0)
{
LSQ_DEBUG("wrote %zd bytes more of duplicate push (%s)",
nw, stream->sm_dup_push_off == stream->sm_dup_push_len ?
"done" : "not done");
if (stream->sm_dup_push_off == stream->sm_dup_push_len)
{
/* Restore want_write flag */
want_write = !!(stream->sm_qflags & SMQF_WANT_WRITE);
if (want_write != stream->sm_saved_want_write)
(void) lsquic_stream_wantwrite(stream,
stream->sm_saved_want_write);
}
}
else if (nw < 0)
{
LSQ_WARN("could not write duplicate push (wrapper)");
/* XXX What should happen if we hit an error? TODO */
}
}
int
lsquic_stream_duplicate_push (struct lsquic_stream *stream, uint64_t push_id)
{
struct lsquic_reader dp_reader;
unsigned bits, len;
ssize_t nw;
assert(stream->sm_bflags & SMBF_IETF);
assert(lsquic_stream_can_push(stream));
bits = vint_val2bits(push_id);
len = 1 << bits;
if (!stream_activate_hq_frame(stream,
stream->sm_payload + stream->sm_n_buffered, HQFT_DUPLICATE_PUSH,
SHF_FIXED_SIZE, len))
return -1;
stream->stream_flags |= STREAM_PUSHING;
stream->sm_dup_push_len = len;
stream->sm_dup_push_off = 0;
vint_write(stream->sm_dup_push_buf, push_id, bits, 1 << bits);
init_dp_reader(stream, &dp_reader);
nw = stream_write(stream, &dp_reader);
if (nw > 0)
{
if (stream->sm_dup_push_off == stream->sm_dup_push_len)
LSQ_DEBUG("fully wrote DUPLICATE_PUSH %"PRIu64, push_id);
else
{
LSQ_DEBUG("partially wrote DUPLICATE_PUSH %"PRIu64, push_id);
stream->stream_flags |= STREAM_NOPUSH;
stream->sm_saved_want_write =
!!(stream->sm_qflags & SMQF_WANT_WRITE);
stream_wantwrite(stream, 1);
}
return 0;
}
else
{
if (nw < 0)
LSQ_WARN("failure writing DUPLICATE_PUSH");
stream->stream_flags |= STREAM_NOPUSH;
stream->stream_flags &= ~STREAM_PUSHING;
return -1;
}
}
static size_t
pp_reader_read (void *lsqr_ctx, void *buf, size_t count)
{

View file

@ -341,10 +341,6 @@ struct lsquic_stream
signed char sm_saved_want_write;
signed char sm_has_frame;
unsigned char sm_dup_push_off;
unsigned char sm_dup_push_len;
unsigned char sm_dup_push_buf[8];
#if LSQUIC_KEEP_STREAM_HISTORY
sm_hist_idx_t sm_hist_idx;
#endif
@ -592,9 +588,6 @@ lsquic_stream_qdec_unblocked (struct lsquic_stream *);
int
lsquic_stream_can_push (const struct lsquic_stream *);
int
lsquic_stream_duplicate_push (struct lsquic_stream *, uint64_t push_id);
int
lsquic_stream_push_promise (struct lsquic_stream *, struct push_promise *);

View file

@ -57,7 +57,7 @@ tpi_val_2_enum (uint64_t tpi_val)
}
static const unsigned short enum_2_tpi_val[LAST_TPI + 1] =
static const unsigned enum_2_tpi_val[LAST_TPI + 1] =
{
[TPI_ORIGINAL_CONNECTION_ID] = 0x0,
[TPI_MAX_IDLE_TIMEOUT] = 0x1,
@ -183,6 +183,500 @@ lsquic_tp_has_pref_ipv6 (const struct transport_params *params)
int
lsquic_tp_encode (const struct transport_params *params, int is_server,
unsigned char *const buf, size_t bufsz)
{
unsigned char *p;
size_t need;
uint16_t u16;
enum transport_param_id tpi;
unsigned set;
unsigned bits[LAST_TPI + 1][3 /* ID, length, value */];
need = 0;
set = params->tp_set; /* Will turn bits off for default values */
if (is_server)
{
if (set & (1 << TPI_ORIGINAL_CONNECTION_ID))
{
bits[TPI_ORIGINAL_CONNECTION_ID][0]
= vint_val2bits(enum_2_tpi_val[TPI_ORIGINAL_CONNECTION_ID]);
#if __GNUC__
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif
bits[TPI_ORIGINAL_CONNECTION_ID][1]
= vint_val2bits(params->tp_original_cid.len);
#if __GNUC__
#pragma GCC diagnostic pop
#pragma GCC diagnostic pop
#endif
need += (1 << bits[TPI_ORIGINAL_CONNECTION_ID][0])
+ (1 << bits[TPI_ORIGINAL_CONNECTION_ID][1])
+ params->tp_original_cid.len;
}
if (set & (1 << TPI_STATELESS_RESET_TOKEN))
{
bits[TPI_STATELESS_RESET_TOKEN][0]
= vint_val2bits(enum_2_tpi_val[TPI_STATELESS_RESET_TOKEN]);
bits[TPI_STATELESS_RESET_TOKEN][1]
= vint_val2bits(sizeof(params->tp_stateless_reset_token));
need += (1 << bits[TPI_STATELESS_RESET_TOKEN][0])
+ (1 << bits[TPI_STATELESS_RESET_TOKEN][1])
+ sizeof(params->tp_stateless_reset_token);
}
if (set & (1 << TPI_PREFERRED_ADDRESS))
{
bits[TPI_PREFERRED_ADDRESS][0]
= vint_val2bits(enum_2_tpi_val[TPI_PREFERRED_ADDRESS]);
bits[TPI_PREFERRED_ADDRESS][1] = vint_val2bits(
preferred_address_size(params));
need += (1 << bits[TPI_PREFERRED_ADDRESS][0])
+ (1 << bits[TPI_PREFERRED_ADDRESS][1])
+ preferred_address_size(params);
}
}
#if LSQUIC_TEST_QUANTUM_READINESS
else if (set & (1 << TPI_QUANTUM_READINESS))
{
bits[TPI_QUANTUM_READINESS][0]
= vint_val2bits(enum_2_tpi_val[TPI_QUANTUM_READINESS]);
bits[TPI_QUANTUM_READINESS][1] = vint_val2bits(QUANTUM_READY_SZ);
need += (1 << bits[TPI_QUANTUM_READINESS][0])
+ (1 << bits[TPI_QUANTUM_READINESS][1])
+ QUANTUM_READY_SZ;
}
#endif
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if (set & (1 << tpi))
{
if (tpi > MAX_NUM_WITH_DEF_TPI
|| params->tp_numerics[tpi] != def_vals[tpi])
{
if (params->tp_numerics[tpi] >= min_vals[tpi]
&& params->tp_numerics[tpi] <= max_vals[tpi])
{
bits[tpi][0] = vint_val2bits(enum_2_tpi_val[tpi]);
bits[tpi][2] = vint_val2bits(params->tp_numerics[tpi]);
bits[tpi][1] = vint_val2bits(bits[tpi][2]);
need += (1 << bits[tpi][0])
+ (1 << bits[tpi][1])
+ (1 << bits[tpi][2]);
}
else if (params->tp_numerics[tpi] > max_vals[tpi])
{
LSQ_DEBUG("numeric value of %s is too large (%"PRIu64" vs "
"maximum of %"PRIu64")", tpi2str[tpi],
params->tp_numerics[tpi], max_vals[tpi]);
return -1;
}
else
{
LSQ_DEBUG("numeric value of %s is too small (%"PRIu64" vs "
"minimum " "of %"PRIu64")",
tpi2str[tpi], params->tp_numerics[tpi], min_vals[tpi]);
return -1;
}
}
else
set &= ~(1 << tpi); /* Don't write default value */
}
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (set & (1 << tpi))
{
bits[tpi][0] = vint_val2bits(enum_2_tpi_val[tpi]);
need += (1 << bits[tpi][0]) + 1 /* Zero length byte */;
}
if (need > bufsz || need > UINT16_MAX)
{
errno = ENOBUFS;
return -1;
}
p = buf;
#define WRITE_TO_P(src, len) do { \
memcpy(p, src, len); \
p += len; \
} while (0)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define WRITE_UINT_TO_P(val, width) do { \
u##width = bswap_##width(val); \
WRITE_TO_P(&u##width, sizeof(u##width)); \
} while (0)
#else
#define WRITE_UINT_TO_P(val, width) do { \
u##width = val; \
WRITE_TO_P(&u##width, sizeof(u##width)); \
} while (0)
#endif
for (tpi = 0; tpi <= LAST_TPI; ++tpi)
if (set & (1 << tpi))
{
vint_write(p, enum_2_tpi_val[tpi], bits[tpi][0],
1 << bits[tpi][0]);
p += 1 << bits[tpi][0];
switch (tpi)
{
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
case TPI_MIN_ACK_DELAY:
vint_write(p, 1 << bits[tpi][2], bits[tpi][1],
1 << bits[tpi][1]);
p += 1 << bits[tpi][1];
vint_write(p, params->tp_numerics[tpi], bits[tpi][2],
1 << bits[tpi][2]);
p += 1 << bits[tpi][2];
break;
case TPI_ORIGINAL_CONNECTION_ID:
vint_write(p, params->tp_original_cid.len, bits[tpi][1],
1 << bits[tpi][1]);
p += 1 << bits[tpi][1];
WRITE_TO_P(params->tp_original_cid.idbuf,
params->tp_original_cid.len);
break;
case TPI_STATELESS_RESET_TOKEN:
vint_write(p, sizeof(params->tp_stateless_reset_token),
bits[tpi][1], 1 << bits[tpi][1]);
p += 1 << bits[tpi][1];
WRITE_TO_P(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token));
break;
case TPI_PREFERRED_ADDRESS:
vint_write(p, preferred_address_size(params),
bits[tpi][1], 1 << bits[tpi][1]);
p += 1 << bits[tpi][1];
WRITE_UINT_TO_P(preferred_address_size(params), 16);
WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, 16);
WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port, 16);
*p++ = params->tp_preferred_address.cid.len;
WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
params->tp_preferred_address.cid.len);
WRITE_TO_P(params->tp_preferred_address.srst,
sizeof(params->tp_preferred_address.srst));
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
*p++ = 0;
break;
#if LSQUIC_TEST_QUANTUM_READINESS
case TPI_QUANTUM_READINESS:
vint_write(p, QUANTUM_READY_SZ,
bits[tpi][1], 1 << bits[tpi][1]);
p += 1 << bits[tpi][1];
memset(p, 'Q', QUANTUM_READY_SZ);
p += QUANTUM_READY_SZ;
break;
#endif
}
}
assert(buf + need == p);
return (int) (p - buf);
#undef WRITE_TO_P
#undef WRITE_UINT_TO_P
}
int
lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
int is_server,
struct transport_params *params)
{
const unsigned char *p, *end, *q;
uint64_t len, param_id;
uint16_t tlen;
enum transport_param_id tpi;
unsigned set_of_ids;
int s;
p = buf;
end = buf + bufsz;
*params = TP_INITIALIZER();
#define EXPECT_LEN(expected_len) do { \
if (expected_len != len) \
return -1; \
} while (0)
#define EXPECT_AT_LEAST(expected_len) do { \
if ((expected_len) > (uintptr_t) (p + len - q)) \
return -1; \
} while (0)
set_of_ids = 0;
while (p < end)
{
s = vint_read(p, end, &param_id);
if (s < 0)
return -1;
p += s;
s = vint_read(p, end, &len);
if (s < 0)
return -1;
p += s;
if ((ptrdiff_t) len > end - p)
return -1;
tpi = tpi_val_2_enum(param_id);
if (tpi <= LAST_TPI)
{
if (set_of_ids & (1 << tpi))
return -1;
set_of_ids |= 1 << tpi;
}
switch (tpi)
{
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
case TPI_MIN_ACK_DELAY:
switch (len)
{
case 1:
case 2:
case 4:
case 8:
s = vint_read(p, p + len, &params->tp_numerics[tpi]);
if (s == (int) len)
{
if (params->tp_numerics[tpi] > max_vals[tpi])
{
LSQ_DEBUG("numeric value of %s is too large "
"(%"PRIu64" vs maximum of %"PRIu64, tpi2str[tpi],
params->tp_numerics[tpi], max_vals[tpi]);
return -1;
}
else if (params->tp_numerics[tpi] < min_vals[tpi])
{
LSQ_DEBUG("numeric value of %s is too small "
"(%"PRIu64" vs minimum of %"PRIu64, tpi2str[tpi],
params->tp_numerics[tpi], min_vals[tpi]);
return -1;
}
break;
}
else
{
LSQ_DEBUG("cannot read the value of numeric transport "
"param %s of length %"PRIu64, tpi2str[tpi], len);
return -1;
}
default:
LSQ_DEBUG("invalid length=%"PRIu64" for numeric transport "
"parameter %s", len, tpi2str[tpi]);
return -1;
}
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
EXPECT_LEN(0);
break;
case TPI_STATELESS_RESET_TOKEN:
/* Client MUST not include reset token,
* see [draft-ietf-quic-transport-11], Section 6.4.1
*/
if (!is_server)
return -1;
EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
memcpy(params->tp_stateless_reset_token, p,
sizeof(params->tp_stateless_reset_token));
break;
case TPI_ORIGINAL_CONNECTION_ID:
/* Client MUST not original connecti ID,
* see [draft-ietf-quic-transport-15], Section 6.6.1
*/
if (!is_server)
return -1;
if (len > MAX_CID_LEN)
return -1;
memcpy(params->tp_original_cid.idbuf, p, len);
params->tp_original_cid.len = len;
break;
case TPI_PREFERRED_ADDRESS:
/* Client MUST not include preferred address,
* see [draft-ietf-quic-transport-12], Section 6.4.1
*/
if (!is_server)
return -1;
q = p;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
memcpy(params->tp_preferred_address.ipv4_addr, q,
sizeof(params->tp_preferred_address.ipv4_addr));
q += sizeof(params->tp_preferred_address.ipv4_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
memcpy(params->tp_preferred_address.ipv6_addr, q,
sizeof(params->tp_preferred_address.ipv6_addr));
q += sizeof(params->tp_preferred_address.ipv6_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(1);
tlen = *q;
q += 1;
if (tlen < 4 || tlen > MAX_CID_LEN)
{
LSQ_DEBUG("preferred server address contains invalid "
"CID length of %"PRIu16" bytes", tlen);
return -1;
}
EXPECT_AT_LEAST(tlen);
memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
params->tp_preferred_address.cid.len = tlen;
q += tlen;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
memcpy(params->tp_preferred_address.srst, q,
sizeof(params->tp_preferred_address.srst));
q += sizeof(params->tp_preferred_address.srst);
if (q != p + len)
return -1;
break;
default:
/* Do nothing: skip this transport parameter */
break;
}
p += len;
if (tpi <= LAST_TPI)
{
params->tp_set |= 1 << tpi;
params->tp_decoded |= 1 << tpi;
}
}
if (p != end)
return -1;
if ((params->tp_set & (1 << TPI_MIN_ACK_DELAY))
&& params->tp_numerics[TPI_MIN_ACK_DELAY]
> params->tp_numerics[TPI_MAX_ACK_DELAY] * 1000)
{
LSQ_DEBUG("min_ack_delay (%"PRIu64" usec) is larger than "
"max_ack_delay (%"PRIu64" ms)",
params->tp_numerics[TPI_MIN_ACK_DELAY],
params->tp_numerics[TPI_MAX_ACK_DELAY]);
return -1;
}
return (int) (end - buf);
#undef EXPECT_LEN
}
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
{
char *const end = buf + sz;
int nw;
enum transport_param_id tpi;
char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
char addr_str[INET6_ADDRSTRLEN];
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if (params->tp_set & (1 << tpi))
{
nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64,
(buf + sz > end) << 1, "; ", tpi2str[tpi],
params->tp_numerics[tpi]);
buf += nw;
if (buf >= end)
return;
}
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[tpi]);
buf += nw;
if (buf >= end)
return;
}
#if LSQUIC_TEST_QUANTUM_READINESS
if (params->tp_set & (1 << TPI_QUANTUM_READINESS))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[TPI_QUANTUM_READINESS]);
buf += nw;
if (buf >= end)
return;
}
#endif
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{
lsquic_hexstr(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
nw = snprintf(buf, end - buf, "; stateless_reset_token: %s", tok_str);
buf += nw;
if (buf >= end)
return;
}
if (params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))
{
char cidbuf_[MAX_CID_LEN * 2 + 1];
nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
CID_BITS(&params->tp_original_cid));
buf += nw;
if (buf >= end)
return;
}
if (lsquic_tp_has_pref_ipv4(params))
{
if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
addr_str, sizeof(addr_str)))
{
nw = snprintf(buf, end - buf, "; IPv4 preferred address: %s:%u",
addr_str, params->tp_preferred_address.ipv4_port);
buf += nw;
if (buf >= end)
return;
}
}
if (lsquic_tp_has_pref_ipv6(params))
{
if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
addr_str, sizeof(addr_str)))
{
nw = snprintf(buf, end - buf, "; IPv6 preferred address: %s:%u",
addr_str, params->tp_preferred_address.ipv6_port);
buf += nw;
if (buf >= end)
return;
}
}
}
int
lsquic_tp_encode_id25 (const struct transport_params *params, int is_server,
unsigned char *const buf, size_t bufsz)
{
unsigned char *p;
size_t need = 2;
@ -348,7 +842,7 @@ lsquic_tp_encode (const struct transport_params *params, int is_server,
int
lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
lsquic_tp_decode_id25 (const unsigned char *const buf, size_t bufsz,
int is_server,
struct transport_params *params)
{
@ -543,86 +1037,3 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
return (int) (end - buf);
#undef EXPECT_LEN
}
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
{
char *const end = buf + sz;
int nw;
enum transport_param_id tpi;
char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
char addr_str[INET6_ADDRSTRLEN];
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if (params->tp_set & (1 << tpi))
{
nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64,
(buf + sz > end) << 1, "; ", tpi2str[tpi],
params->tp_numerics[tpi]);
buf += nw;
if (buf >= end)
return;
}
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[tpi]);
buf += nw;
if (buf >= end)
return;
}
#if LSQUIC_TEST_QUANTUM_READINESS
if (params->tp_set & (1 << TPI_QUANTUM_READINESS))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[TPI_QUANTUM_READINESS]);
buf += nw;
if (buf >= end)
return;
}
#endif
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{
lsquic_hexstr(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
nw = snprintf(buf, end - buf, "; stateless_reset_token: %s", tok_str);
buf += nw;
if (buf >= end)
return;
}
if (params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))
{
char cidbuf_[MAX_CID_LEN * 2 + 1];
nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
CID_BITS(&params->tp_original_cid));
buf += nw;
if (buf >= end)
return;
}
if (lsquic_tp_has_pref_ipv4(params))
{
if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
addr_str, sizeof(addr_str)))
{
nw = snprintf(buf, end - buf, "; IPv4 preferred address: %s:%u",
addr_str, params->tp_preferred_address.ipv4_port);
buf += nw;
if (buf >= end)
return;
}
}
if (lsquic_tp_has_pref_ipv6(params))
{
if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
addr_str, sizeof(addr_str)))
{
nw = snprintf(buf, end - buf, "; IPv6 preferred address: %s:%u",
addr_str, params->tp_preferred_address.ipv6_port);
buf += nw;
if (buf >= end)
return;
}
}
}

View file

@ -134,6 +134,14 @@ lsquic_tp_decode (const unsigned char *buf, size_t bufsz,
int is_server,
struct transport_params *);
int
lsquic_tp_encode_id25 (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz);
int
lsquic_tp_decode_id25 (const unsigned char *buf, size_t bufsz,
int is_server, struct transport_params *);
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);

View file

@ -6,7 +6,7 @@
/* See [draft-ietf-quic-transport-11], section-7.1 */
#define vint_val2bits(val) ( \
(val >= (1 << 6)) + (val >= (1 << 14)) + (val >= (1 << 30)))
((val) >= (1 << 6)) + ((val) >= (1 << 14)) + ((val) >= (1 << 30)))
#define vint_size(val) (1u << vint_val2bits(val))

View file

@ -14,8 +14,8 @@ static const unsigned char version_tags[N_LSQVER][4] =
#if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', },
#endif
[LSQVER_ID24] = { 0xFF, 0, 0, 24, },
[LSQVER_ID25] = { 0xFF, 0, 0, 25, },
[LSQVER_ID27] = { 0xFF, 0, 0, 27, },
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
};
@ -52,8 +52,8 @@ const char *const lsquic_ver2str[N_LSQVER] = {
#if LSQUIC_USE_Q098
[LSQVER_098] = "Q098",
#endif
[LSQVER_ID24] = "FF000018",
[LSQVER_ID25] = "FF000019",
[LSQVER_ID27] = "FF00001B",
[LSQVER_VERNEG] = "FAFAFAFA",
};