mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.6.0
- [FEATURE] QUIC and HTTP/3 Internet Draft 24 support
This commit is contained in:
parent
75a7a2a36a
commit
03e6b668ec
20 changed files with 514 additions and 124 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
2019-11-07
|
||||||
|
- 2.6.0
|
||||||
|
- [FEATURE] QUIC and HTTP/3 Internet Draft 24 support
|
||||||
|
|
||||||
2019-11-07
|
2019-11-07
|
||||||
- 2.5.2
|
- 2.5.2
|
||||||
- [BUGFIX] argument order to gQUIC client constructor. Regression
|
- [BUGFIX] argument order to gQUIC client constructor. Regression
|
||||||
|
|
|
@ -49,7 +49,8 @@ IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O0 -g3")
|
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O0 -g3")
|
||||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Werror")
|
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Werror")
|
||||||
IF(CMAKE_C_COMPILER MATCHES "clang" AND
|
IF(CMAKE_C_COMPILER MATCHES "clang" AND
|
||||||
NOT "$ENV{TRAVIS}" MATCHES "^true$")
|
NOT "$ENV{TRAVIS}" MATCHES "^true$" AND
|
||||||
|
NOT "$ENV{EXTRA_CFLAGS}" MATCHES "-fsanitize")
|
||||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fsanitize=address")
|
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fsanitize=address")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
# Uncomment to enable cleartext protocol mode (no crypto):
|
# Uncomment to enable cleartext protocol mode (no crypto):
|
||||||
|
|
|
@ -24,8 +24,8 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LSQUIC_MAJOR_VERSION 2
|
#define LSQUIC_MAJOR_VERSION 2
|
||||||
#define LSQUIC_MINOR_VERSION 5
|
#define LSQUIC_MINOR_VERSION 6
|
||||||
#define LSQUIC_PATCH_VERSION 2
|
#define LSQUIC_PATCH_VERSION 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engine flags:
|
* Engine flags:
|
||||||
|
@ -129,6 +129,11 @@ enum lsquic_version
|
||||||
*/
|
*/
|
||||||
LSQVER_ID23,
|
LSQVER_ID23,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IETF QUIC Draft-24
|
||||||
|
*/
|
||||||
|
LSQVER_ID24,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special version to trigger version negotiation.
|
* Special version to trigger version negotiation.
|
||||||
* [draft-ietf-quic-transport-11], Section 3.
|
* [draft-ietf-quic-transport-11], Section 3.
|
||||||
|
@ -156,9 +161,11 @@ enum lsquic_version
|
||||||
|
|
||||||
#define LSQUIC_GQUIC_HEADER_VERSIONS ((1 << LSQVER_039) | (1 << LSQVER_043))
|
#define LSQUIC_GQUIC_HEADER_VERSIONS ((1 << LSQVER_039) | (1 << LSQVER_043))
|
||||||
|
|
||||||
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID23) | (1 << LSQVER_VERNEG))
|
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID23) | (1 << LSQVER_ID24) \
|
||||||
|
| (1 << LSQVER_VERNEG))
|
||||||
|
|
||||||
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID23) | (1 << LSQVER_VERNEG))
|
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID23) | (1 << LSQVER_ID24) \
|
||||||
|
| (1 << LSQVER_VERNEG))
|
||||||
|
|
||||||
enum lsquic_hsk_status
|
enum lsquic_hsk_status
|
||||||
{
|
{
|
||||||
|
|
|
@ -321,6 +321,7 @@ extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
|
||||||
|
|
||||||
#define select_esf_common_by_ver(ver) ( \
|
#define select_esf_common_by_ver(ver) ( \
|
||||||
ver == LSQVER_ID23 ? &lsquic_enc_session_common_ietf_v1 : \
|
ver == LSQVER_ID23 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||||
|
ver == LSQVER_ID24 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||||
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
|
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
|
||||||
&lsquic_enc_session_common_gquic_1 )
|
&lsquic_enc_session_common_gquic_1 )
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ static const struct alpn_map {
|
||||||
enum lsquic_version version;
|
enum lsquic_version version;
|
||||||
const unsigned char *alpn;
|
const unsigned char *alpn;
|
||||||
} s_alpns[] = {
|
} s_alpns[] = {
|
||||||
|
{ LSQVER_ID24, (unsigned char *) "\x05h3-24", },
|
||||||
{ LSQVER_ID23, (unsigned char *) "\x05h3-23", },
|
{ LSQVER_ID23, (unsigned char *) "\x05h3-23", },
|
||||||
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-23", },
|
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-23", },
|
||||||
};
|
};
|
||||||
|
@ -509,6 +510,14 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *s = getenv("LSQUIC_TEST_QUANTUM_READINESS");
|
||||||
|
if (s && atoi(s))
|
||||||
|
params.tp_flags |= TRAPA_QUANTUM_READY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
params.tp_init_max_data = settings->es_init_max_data;
|
params.tp_init_max_data = settings->es_init_max_data;
|
||||||
params.tp_init_max_stream_data_bidi_local
|
params.tp_init_max_stream_data_bidi_local
|
||||||
= settings->es_init_max_stream_data_bidi_local;
|
= settings->es_init_max_stream_data_bidi_local;
|
||||||
|
@ -1224,7 +1233,11 @@ init_client (struct enc_sess_iquic *const enc_sess)
|
||||||
int transpa_len;
|
int transpa_len;
|
||||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||||
#define hexbuf errbuf /* This is a dual-purpose buffer */
|
#define hexbuf errbuf /* This is a dual-purpose buffer */
|
||||||
unsigned char trans_params[0x80];
|
unsigned char trans_params[0x80
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
+ 4 + QUANTUM_READY_SZ
|
||||||
|
#endif
|
||||||
|
];
|
||||||
|
|
||||||
for (am = s_alpns; am < s_alpns + sizeof(s_alpns)
|
for (am = s_alpns; am < s_alpns + sizeof(s_alpns)
|
||||||
/ sizeof(s_alpns[0]); ++am)
|
/ sizeof(s_alpns[0]); ++am)
|
||||||
|
@ -1779,6 +1792,22 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct ku_label
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
uint8_t len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
select_ku_label (const struct enc_sess_iquic *enc_sess)
|
||||||
|
{
|
||||||
|
if (enc_sess->esi_conn->cn_version == LSQVER_ID23)
|
||||||
|
return (struct ku_label) { "traffic upd", 11, };
|
||||||
|
else
|
||||||
|
return (struct ku_label) { "quic ku", 7, };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static enum dec_packin
|
static enum dec_packin
|
||||||
iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
||||||
struct lsquic_engine_public *enpub, const struct lsquic_conn *lconn,
|
struct lsquic_engine_public *enpub, const struct lsquic_conn *lconn,
|
||||||
|
@ -1859,9 +1888,10 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
||||||
|| packet_in->pi_packno
|
|| packet_in->pi_packno
|
||||||
> enc_sess->esi_pairs[enc_sess->esi_key_phase].ykp_thresh)
|
> enc_sess->esi_pairs[enc_sess->esi_key_phase].ykp_thresh)
|
||||||
{
|
{
|
||||||
|
const struct ku_label kl = select_ku_label(enc_sess);
|
||||||
lsquic_qhkdf_expand(enc_sess->esi_md,
|
lsquic_qhkdf_expand(enc_sess->esi_md,
|
||||||
enc_sess->esi_traffic_secrets[cliser], enc_sess->esi_trasec_sz,
|
enc_sess->esi_traffic_secrets[cliser], enc_sess->esi_trasec_sz,
|
||||||
"traffic upd", 11, new_secret, enc_sess->esi_trasec_sz);
|
kl.str, kl.len, new_secret, enc_sess->esi_trasec_sz);
|
||||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||||
LSQ_DEBUG("key phase changed to %u, will try decrypting using "
|
LSQ_DEBUG("key phase changed to %u, will try decrypting using "
|
||||||
"new secret %s", key_phase, HEXSTR(new_secret,
|
"new secret %s", key_phase, HEXSTR(new_secret,
|
||||||
|
@ -1959,6 +1989,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("decryption in the new key phase %u successful, rotate "
|
LSQ_DEBUG("decryption in the new key phase %u successful, rotate "
|
||||||
"keys", key_phase);
|
"keys", key_phase);
|
||||||
|
const struct ku_label kl = select_ku_label(enc_sess);
|
||||||
pair = &enc_sess->esi_pairs[ key_phase ];
|
pair = &enc_sess->esi_pairs[ key_phase ];
|
||||||
pair->ykp_thresh = packet_in->pi_packno;
|
pair->ykp_thresh = packet_in->pi_packno;
|
||||||
pair->ykp_ctx[ cliser ] = crypto_ctx_buf;
|
pair->ykp_ctx[ cliser ] = crypto_ctx_buf;
|
||||||
|
@ -1966,7 +1997,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
||||||
enc_sess->esi_trasec_sz);
|
enc_sess->esi_trasec_sz);
|
||||||
lsquic_qhkdf_expand(enc_sess->esi_md,
|
lsquic_qhkdf_expand(enc_sess->esi_md,
|
||||||
enc_sess->esi_traffic_secrets[!cliser], enc_sess->esi_trasec_sz,
|
enc_sess->esi_traffic_secrets[!cliser], enc_sess->esi_trasec_sz,
|
||||||
"traffic upd", 11, new_secret, enc_sess->esi_trasec_sz);
|
kl.str, kl.len, new_secret, enc_sess->esi_trasec_sz);
|
||||||
memcpy(enc_sess->esi_traffic_secrets[ !cliser ], new_secret,
|
memcpy(enc_sess->esi_traffic_secrets[ !cliser ], new_secret,
|
||||||
enc_sess->esi_trasec_sz);
|
enc_sess->esi_trasec_sz);
|
||||||
s = init_crypto_ctx(&pair->ykp_ctx[ !cliser ], enc_sess->esi_md,
|
s = init_crypto_ctx(&pair->ykp_ctx[ !cliser ], enc_sess->esi_md,
|
||||||
|
|
|
@ -1234,7 +1234,7 @@ find_conn_by_srst (struct lsquic_engine *engine,
|
||||||
static int
|
static int
|
||||||
process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||||
struct packin_parse_state *ppstate, const struct sockaddr *sa_local,
|
struct packin_parse_state *ppstate, const struct sockaddr *sa_local,
|
||||||
const struct sockaddr *sa_peer, void *peer_ctx)
|
const struct sockaddr *sa_peer, void *peer_ctx, int full_udp_packet)
|
||||||
{
|
{
|
||||||
lsquic_conn_t *conn;
|
lsquic_conn_t *conn;
|
||||||
const unsigned char *packet_in_data;
|
const unsigned char *packet_in_data;
|
||||||
|
@ -1257,6 +1257,7 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||||
if (!conn)
|
if (!conn)
|
||||||
{
|
{
|
||||||
if (engine->pub.enp_settings.es_honor_prst
|
if (engine->pub.enp_settings.es_honor_prst
|
||||||
|
&& full_udp_packet
|
||||||
&& !(packet_in->pi_flags & PI_GQUIC)
|
&& !(packet_in->pi_flags & PI_GQUIC)
|
||||||
&& engine->pub.enp_srst_hash
|
&& engine->pub.enp_srst_hash
|
||||||
&& (conn = find_conn_by_srst(engine, packet_in)))
|
&& (conn = find_conn_by_srst(engine, packet_in)))
|
||||||
|
@ -2562,7 +2563,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
|
||||||
packet_in->pi_flags |= (3 & ecn) << PIBIT_ECN_SHIFT;
|
packet_in->pi_flags |= (3 & ecn) << PIBIT_ECN_SHIFT;
|
||||||
eng_hist_inc(&engine->history, packet_in->pi_received, sl_packets_in);
|
eng_hist_inc(&engine->history, packet_in->pi_received, sl_packets_in);
|
||||||
s = process_packet_in(engine, packet_in, &ppstate, sa_local, sa_peer,
|
s = process_packet_in(engine, packet_in, &ppstate, sa_local, sa_peer,
|
||||||
peer_ctx);
|
peer_ctx, packet_in->pi_data_sz == packet_in_size);
|
||||||
n_zeroes += s == 0;
|
n_zeroes += s == 0;
|
||||||
}
|
}
|
||||||
while (0 == s && packet_in_data < packet_end);
|
while (0 == s && packet_in_data < packet_end);
|
||||||
|
|
|
@ -4792,7 +4792,7 @@ process_max_streams_frame (struct ietf_full_conn *conn,
|
||||||
|
|
||||||
if (max_stream_id > VINT_MAX_VALUE)
|
if (max_stream_id > VINT_MAX_VALUE)
|
||||||
{
|
{
|
||||||
ABORT_QUIETLY(0, TEC_STREAM_LIMIT_ERROR,
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR,
|
||||||
"MAX_STREAMS: max %s stream ID of %"PRIu64" exceeds maximum "
|
"MAX_STREAMS: max %s stream ID of %"PRIu64" exceeds maximum "
|
||||||
"stream ID", sd == SD_BIDI ? "bidi" : "uni", max_stream_id);
|
"stream ID", sd == SD_BIDI ? "bidi" : "uni", max_stream_id);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4880,7 +4880,12 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,
|
||||||
parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_conn_id(p, len,
|
parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_conn_id(p, len,
|
||||||
&seqno, &retire_prior_to, &cid, &token);
|
&seqno, &retire_prior_to, &cid, &token);
|
||||||
if (parsed_len < 0)
|
if (parsed_len < 0)
|
||||||
|
{
|
||||||
|
if (parsed_len == -2)
|
||||||
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR,
|
||||||
|
"NEW_CONNECTION_ID contains invalid CID length");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (seqno > UINT32_MAX || retire_prior_to > UINT32_MAX)
|
if (seqno > UINT32_MAX || retire_prior_to > UINT32_MAX)
|
||||||
{ /* It is wasteful to use 8-byte integers for these counters, so this
|
{ /* It is wasteful to use 8-byte integers for these counters, so this
|
||||||
|
@ -4893,7 +4898,7 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,
|
||||||
|
|
||||||
if (retire_prior_to > seqno)
|
if (retire_prior_to > seqno)
|
||||||
{
|
{
|
||||||
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR,
|
||||||
"NEW_CONNECTION_ID: Retire Prior To=%"PRIu64" is larger then the "
|
"NEW_CONNECTION_ID: Retire Prior To=%"PRIu64" is larger then the "
|
||||||
"Sequence Number=%"PRIu64, retire_prior_to, seqno);
|
"Sequence Number=%"PRIu64, retire_prior_to, seqno);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5044,7 +5049,7 @@ process_retire_connection_id_frame (struct ietf_full_conn *conn,
|
||||||
{
|
{
|
||||||
if (LSQUIC_CIDS_EQ(&cce->cce_cid, &packet_in->pi_dcid))
|
if (LSQUIC_CIDS_EQ(&cce->cce_cid, &packet_in->pi_dcid))
|
||||||
{
|
{
|
||||||
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION, "cannot retire CID "
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR, "cannot retire CID "
|
||||||
"seqno=%"PRIu64", for it is used as DCID in the packet", seqno);
|
"seqno=%"PRIu64", for it is used as DCID in the packet", seqno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5071,6 +5076,13 @@ process_new_token_frame (struct ietf_full_conn *conn,
|
||||||
if (parsed_len < 0)
|
if (parsed_len < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (0 == token_sz)
|
||||||
|
{
|
||||||
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR, "received an empty "
|
||||||
|
"NEW_TOKEN frame");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG)
|
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG)
|
||||||
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))
|
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))
|
||||||
{
|
{
|
||||||
|
@ -5129,6 +5141,7 @@ static unsigned
|
||||||
process_streams_blocked_frame (struct ietf_full_conn *conn,
|
process_streams_blocked_frame (struct ietf_full_conn *conn,
|
||||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
|
lsquic_stream_id_t max_stream_id;
|
||||||
uint64_t stream_limit;
|
uint64_t stream_limit;
|
||||||
enum stream_dir sd;
|
enum stream_dir sd;
|
||||||
int parsed_len;
|
int parsed_len;
|
||||||
|
@ -5138,6 +5151,15 @@ process_streams_blocked_frame (struct ietf_full_conn *conn,
|
||||||
if (parsed_len < 0)
|
if (parsed_len < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
max_stream_id = stream_limit << SIT_SHIFT;
|
||||||
|
if (max_stream_id > VINT_MAX_VALUE)
|
||||||
|
{
|
||||||
|
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR,
|
||||||
|
"STREAMS_BLOCKED: max %s stream ID of %"PRIu64" exceeds maximum "
|
||||||
|
"stream ID", sd == SD_BIDI ? "bidi" : "uni", max_stream_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
LSQ_DEBUG("received STREAMS_BLOCKED frame: limited to %"PRIu64
|
LSQ_DEBUG("received STREAMS_BLOCKED frame: limited to %"PRIu64
|
||||||
" %sdirectional stream%.*s", stream_limit, sd == SD_UNI ? "uni" : "bi",
|
" %sdirectional stream%.*s", stream_limit, sd == SD_UNI ? "uni" : "bi",
|
||||||
stream_limit != 1, "s");
|
stream_limit != 1, "s");
|
||||||
|
@ -5257,6 +5279,9 @@ init_new_path (struct ietf_full_conn *conn, struct conn_path *path,
|
||||||
}
|
}
|
||||||
else if (!dcid_changed)
|
else if (!dcid_changed)
|
||||||
{
|
{
|
||||||
|
/* It is OK to reuse DCID if the peer did not use a new DCID when its
|
||||||
|
* address changed. See [draft-ietf-quic-transport-24] Section 9.5.
|
||||||
|
*/
|
||||||
path->cop_path.np_dcid = CUR_NPATH(conn)->np_dcid;
|
path->cop_path.np_dcid = CUR_NPATH(conn)->np_dcid;
|
||||||
LSQ_DEBUGC("assigned already-used DCID %"CID_FMT" to new path %u, "
|
LSQ_DEBUGC("assigned already-used DCID %"CID_FMT" to new path %u, "
|
||||||
"as incoming DCID did not change",
|
"as incoming DCID did not change",
|
||||||
|
@ -5422,7 +5447,6 @@ process_retry_packet (struct ietf_full_conn *conn,
|
||||||
struct lsquic_packet_in *packet_in)
|
struct lsquic_packet_in *packet_in)
|
||||||
{
|
{
|
||||||
lsquic_cid_t scid;
|
lsquic_cid_t scid;
|
||||||
int cidlen_diff;
|
|
||||||
|
|
||||||
if (conn->ifc_flags & (IFC_SERVER|IFC_RETRIED))
|
if (conn->ifc_flags & (IFC_SERVER|IFC_RETRIED))
|
||||||
{
|
{
|
||||||
|
@ -5439,10 +5463,9 @@ process_retry_packet (struct ietf_full_conn *conn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cidlen_diff = (int) CUR_DCID(conn)->len - (int) packet_in->pi_scid_len;
|
|
||||||
if (0 != lsquic_send_ctl_retry(&conn->ifc_send_ctl,
|
if (0 != lsquic_send_ctl_retry(&conn->ifc_send_ctl,
|
||||||
packet_in->pi_data + packet_in->pi_token,
|
packet_in->pi_data + packet_in->pi_token,
|
||||||
packet_in->pi_token_size, cidlen_diff))
|
packet_in->pi_token_size))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
lsquic_scid_from_packet_in(packet_in, &scid);
|
lsquic_scid_from_packet_in(packet_in, &scid);
|
||||||
|
@ -5700,11 +5723,23 @@ process_regular_packet (struct ietf_full_conn *conn,
|
||||||
packet_in->pi_received);
|
packet_in->pi_received);
|
||||||
switch (st) {
|
switch (st) {
|
||||||
case REC_ST_OK:
|
case REC_ST_OK:
|
||||||
if (!(conn->ifc_flags & (
|
if (!(conn->ifc_flags & (IFC_SERVER|IFC_DCID_SET))
|
||||||
IFC_SERVER|
|
|
||||||
IFC_DCID_SET))
|
|
||||||
&& (packet_in->pi_scid_len))
|
&& (packet_in->pi_scid_len))
|
||||||
{
|
{
|
||||||
|
if (CUR_DCID(conn)->len == packet_in->pi_scid_len
|
||||||
|
&& 0 == memcmp(CUR_DCID(conn)->idbuf,
|
||||||
|
packet_in->pi_data + packet_in->pi_scid_off,
|
||||||
|
packet_in->pi_scid_len))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* [draft-ietf-quic-transport-24] Section 17.2.5:
|
||||||
|
" A client MUST discard a Retry packet that contains a Source
|
||||||
|
" Connection ID field that is identical to the Destination
|
||||||
|
" Connection ID field of its Initial packet.
|
||||||
|
*/
|
||||||
|
LSQ_DEBUG("server provided same SCID as ODCID: discard packet");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
conn->ifc_flags |= IFC_DCID_SET;
|
conn->ifc_flags |= IFC_DCID_SET;
|
||||||
lsquic_scid_from_packet_in(packet_in, CUR_DCID(conn));
|
lsquic_scid_from_packet_in(packet_in, CUR_DCID(conn));
|
||||||
LSQ_DEBUGC("set DCID to %"CID_FMT,
|
LSQ_DEBUGC("set DCID to %"CID_FMT,
|
||||||
|
@ -5740,10 +5775,14 @@ process_regular_packet (struct ietf_full_conn *conn,
|
||||||
frame_types &= ~(1 << QUIC_FRAME_PING);
|
frame_types &= ~(1 << QUIC_FRAME_PING);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
was_missing = packet_in->pi_packno !=
|
if (frame_types & IQUIC_FRAME_ACKABLE_MASK)
|
||||||
|
{
|
||||||
|
was_missing = packet_in->pi_packno !=
|
||||||
lsquic_rechist_largest_packno(&conn->ifc_rechist[pns]);
|
lsquic_rechist_largest_packno(&conn->ifc_rechist[pns]);
|
||||||
conn->ifc_n_slack_akbl[pns]
|
++conn->ifc_n_slack_akbl[pns];
|
||||||
+= !!(frame_types & IQUIC_FRAME_ACKABLE_MASK);
|
}
|
||||||
|
else
|
||||||
|
was_missing = 0;
|
||||||
try_queueing_ack(conn, pns, was_missing, packet_in->pi_received);
|
try_queueing_ack(conn, pns, was_missing, packet_in->pi_received);
|
||||||
}
|
}
|
||||||
conn->ifc_incoming_ecn <<= 1;
|
conn->ifc_incoming_ecn <<= 1;
|
||||||
|
|
|
@ -218,29 +218,127 @@ imico_stream_flush (void *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct stream_frame *
|
||||||
|
imico_find_stream_frame (const struct ietf_mini_conn *conn,
|
||||||
|
enum enc_level enc_level, unsigned read_off)
|
||||||
|
{
|
||||||
|
struct stream_frame *frame;
|
||||||
|
|
||||||
|
if (conn->imc_last_in.frame && enc_level == conn->imc_last_in.enc_level
|
||||||
|
&& read_off == DF_ROFF(conn->imc_last_in.frame))
|
||||||
|
return conn->imc_last_in.frame;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(frame, &conn->imc_crypto_frames, next_frame)
|
||||||
|
if (enc_level == frame->stream_id && read_off == DF_ROFF(frame))
|
||||||
|
return frame;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
imico_read_chlo_size (struct ietf_mini_conn *conn, const unsigned char *buf,
|
||||||
|
size_t sz)
|
||||||
|
{
|
||||||
|
const unsigned char *const end = buf + sz;
|
||||||
|
|
||||||
|
assert(conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off < 4);
|
||||||
|
switch (conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (buf == end)
|
||||||
|
return;
|
||||||
|
if (*buf != 1)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("Does not begin with ClientHello");
|
||||||
|
conn->imc_flags |= IMC_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++buf;
|
||||||
|
/* fall-through */
|
||||||
|
case 1:
|
||||||
|
if (buf == end)
|
||||||
|
return;
|
||||||
|
if (*buf != 0)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("ClientHello larger than 16K");
|
||||||
|
conn->imc_flags |= IMC_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++buf;
|
||||||
|
/* fall-through */
|
||||||
|
case 2:
|
||||||
|
if (buf == end)
|
||||||
|
return;
|
||||||
|
conn->imc_ch_len = *buf << 8;
|
||||||
|
++buf;
|
||||||
|
/* fall-through */
|
||||||
|
default:
|
||||||
|
if (buf == end)
|
||||||
|
return;
|
||||||
|
conn->imc_ch_len |= *buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
imico_chlo_has_been_consumed (const struct ietf_mini_conn *conn)
|
||||||
|
{
|
||||||
|
return conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off > 3
|
||||||
|
&& conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off >= conn->imc_ch_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
imico_stream_readf (void *stream,
|
imico_stream_readf (void *stream,
|
||||||
size_t (*readf)(void *, const unsigned char *, size_t, int), void *ctx)
|
size_t (*readf)(void *, const unsigned char *, size_t, int), void *ctx)
|
||||||
{
|
{
|
||||||
struct mini_crypto_stream *const cryst = stream;
|
struct mini_crypto_stream *const cryst = stream;
|
||||||
struct ietf_mini_conn *const conn = cryst_get_conn(cryst);
|
struct ietf_mini_conn *const conn = cryst_get_conn(cryst);
|
||||||
struct stream_frame *frame = conn->imc_last_in.frame;
|
struct stream_frame *frame;
|
||||||
size_t nread;
|
const unsigned char *buf;
|
||||||
|
size_t nread, total_read;
|
||||||
|
unsigned avail;
|
||||||
|
|
||||||
if (cryst->mcs_enc_level == conn->imc_last_in.enc_level
|
total_read = 0;
|
||||||
&& frame && cryst->mcs_read_off == DF_ROFF(frame))
|
while ((frame = imico_find_stream_frame(conn, cryst->mcs_enc_level,
|
||||||
|
cryst->mcs_read_off)))
|
||||||
{
|
{
|
||||||
nread = readf(ctx, frame->data_frame.df_data
|
avail = DF_SIZE(frame) - frame->data_frame.df_read_off;
|
||||||
+ frame->data_frame.df_read_off, DF_SIZE(frame)
|
buf = frame->data_frame.df_data + frame->data_frame.df_read_off;
|
||||||
- frame->data_frame.df_read_off, DF_FIN(frame));
|
nread = readf(ctx, buf, avail, DF_FIN(frame));
|
||||||
|
if (cryst->mcs_enc_level == ENC_LEV_CLEAR && cryst->mcs_read_off < 4)
|
||||||
|
imico_read_chlo_size(conn, buf, nread);
|
||||||
|
total_read += nread;
|
||||||
cryst->mcs_read_off += nread;
|
cryst->mcs_read_off += nread;
|
||||||
frame->data_frame.df_read_off += nread;
|
frame->data_frame.df_read_off += nread;
|
||||||
LSQ_DEBUG("read %zu bytes at offset %"PRIu64" on enc level %u", nread,
|
LSQ_DEBUG("read %zu bytes at offset %"PRIu64" on enc level %u", nread,
|
||||||
DF_ROFF(frame), cryst->mcs_enc_level);
|
DF_ROFF(frame), cryst->mcs_enc_level);
|
||||||
return nread;
|
if (DF_END(frame) == DF_ROFF(frame))
|
||||||
|
{
|
||||||
|
if (frame == conn->imc_last_in.frame)
|
||||||
|
conn->imc_last_in.frame = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&conn->imc_crypto_frames, frame, next_frame);
|
||||||
|
--conn->imc_n_crypto_frames;
|
||||||
|
conn->imc_crypto_frames_sz -= DF_SIZE(frame);
|
||||||
|
lsquic_packet_in_put(&conn->imc_enpub->enp_mm,
|
||||||
|
frame->packet_in);
|
||||||
|
lsquic_malo_put(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nread < avail)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (total_read > 0)
|
||||||
|
return total_read;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* CRYPTO streams never end, so zero bytes read always means
|
||||||
|
* EWOULDBLOCK
|
||||||
|
*/
|
||||||
errno = EWOULDBLOCK;
|
errno = EWOULDBLOCK;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -376,6 +474,9 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
||||||
conn->imc_conn.cn_esf_c = select_esf_common_by_ver(version);
|
conn->imc_conn.cn_esf_c = select_esf_common_by_ver(version);
|
||||||
TAILQ_INIT(&conn->imc_packets_out);
|
TAILQ_INIT(&conn->imc_packets_out);
|
||||||
TAILQ_INIT(&conn->imc_app_packets);
|
TAILQ_INIT(&conn->imc_app_packets);
|
||||||
|
TAILQ_INIT(&conn->imc_crypto_frames);
|
||||||
|
if (odcid)
|
||||||
|
conn->imc_flags |= IMC_ADDR_VALIDATED;
|
||||||
|
|
||||||
LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
|
LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
|
||||||
conn, conn->imc_path.np_pack_size);
|
conn, conn->imc_path.np_pack_size);
|
||||||
|
@ -396,6 +497,7 @@ ietf_mini_conn_ci_destroy (struct lsquic_conn *lconn)
|
||||||
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
|
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
|
||||||
struct lsquic_packet_out *packet_out;
|
struct lsquic_packet_out *packet_out;
|
||||||
struct lsquic_packet_in *packet_in;
|
struct lsquic_packet_in *packet_in;
|
||||||
|
struct stream_frame *frame;
|
||||||
|
|
||||||
while ((packet_out = TAILQ_FIRST(&conn->imc_packets_out)))
|
while ((packet_out = TAILQ_FIRST(&conn->imc_packets_out)))
|
||||||
{
|
{
|
||||||
|
@ -407,6 +509,12 @@ ietf_mini_conn_ci_destroy (struct lsquic_conn *lconn)
|
||||||
TAILQ_REMOVE(&conn->imc_app_packets, packet_in, pi_next);
|
TAILQ_REMOVE(&conn->imc_app_packets, packet_in, pi_next);
|
||||||
lsquic_packet_in_put(&conn->imc_enpub->enp_mm, packet_in);
|
lsquic_packet_in_put(&conn->imc_enpub->enp_mm, packet_in);
|
||||||
}
|
}
|
||||||
|
while ((frame = TAILQ_FIRST(&conn->imc_crypto_frames)))
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&conn->imc_crypto_frames, frame, next_frame);
|
||||||
|
lsquic_packet_in_put(&conn->imc_enpub->enp_mm, frame->packet_in);
|
||||||
|
lsquic_malo_put(frame);
|
||||||
|
}
|
||||||
if (lconn->cn_enc_session)
|
if (lconn->cn_enc_session)
|
||||||
lconn->cn_esf.i->esfi_destroy(lconn->cn_enc_session);
|
lconn->cn_esf.i->esfi_destroy(lconn->cn_enc_session);
|
||||||
LSQ_DEBUG("ietf_mini_conn_ci_destroyed");
|
LSQ_DEBUG("ietf_mini_conn_ci_destroyed");
|
||||||
|
@ -602,6 +710,44 @@ imico_process_stream_frame (IMICO_PROC_FRAME_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
imico_stash_stream_frame (struct ietf_mini_conn *conn,
|
||||||
|
enum enc_level enc_level, struct lsquic_packet_in *packet_in,
|
||||||
|
const struct stream_frame *frame)
|
||||||
|
{
|
||||||
|
struct stream_frame *copy;
|
||||||
|
|
||||||
|
if (conn->imc_n_crypto_frames >= IMICO_MAX_STASHED_FRAMES)
|
||||||
|
{
|
||||||
|
LSQ_INFO("cannot stash more CRYPTO frames, at %hhu already, while max "
|
||||||
|
"is %u", conn->imc_n_crypto_frames, IMICO_MAX_STASHED_FRAMES);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->imc_crypto_frames_sz + DF_SIZE(frame) > IMICO_MAX_BUFFERED_CRYPTO)
|
||||||
|
{
|
||||||
|
LSQ_INFO("cannot stash more than %u bytes of CRYPTO frames",
|
||||||
|
IMICO_MAX_BUFFERED_CRYPTO);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy = lsquic_malo_get(conn->imc_enpub->enp_mm.malo.stream_frame);
|
||||||
|
if (!copy)
|
||||||
|
{
|
||||||
|
LSQ_INFO("could not allocate stream frame for stashing");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*copy = *frame;
|
||||||
|
copy->packet_in = lsquic_packet_in_get(packet_in);
|
||||||
|
copy->stream_id = enc_level;
|
||||||
|
TAILQ_INSERT_TAIL(&conn->imc_crypto_frames, copy, next_frame);
|
||||||
|
++conn->imc_n_crypto_frames;
|
||||||
|
conn->imc_crypto_frames_sz += DF_SIZE(frame);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
imico_process_crypto_frame (IMICO_PROC_FRAME_ARGS)
|
imico_process_crypto_frame (IMICO_PROC_FRAME_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -618,11 +764,19 @@ imico_process_crypto_frame (IMICO_PROC_FRAME_ARGS)
|
||||||
enc_level = lsquic_packet_in_enc_level(packet_in);
|
enc_level = lsquic_packet_in_enc_level(packet_in);
|
||||||
EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame, enc_level);
|
EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame, enc_level);
|
||||||
|
|
||||||
if (!(conn->imc_streams[enc_level].mcs_flags & MCS_CREATED)
|
if (conn->imc_streams[enc_level].mcs_read_off >= DF_OFF(&stream_frame)
|
||||||
|| conn->imc_streams[enc_level].mcs_read_off <
|
&& conn->imc_streams[enc_level].mcs_read_off < DF_END(&stream_frame))
|
||||||
stream_frame.data_frame.df_offset
|
|
||||||
+ stream_frame.data_frame.df_size)
|
|
||||||
LSQ_DEBUG("Got CRYPTO frame for enc level #%u", enc_level);
|
LSQ_DEBUG("Got CRYPTO frame for enc level #%u", enc_level);
|
||||||
|
else if (conn->imc_streams[enc_level].mcs_read_off < DF_OFF(&stream_frame))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("Can't read CRYPTO frame on enc level #%u at offset %"PRIu64
|
||||||
|
" yet -- stash", enc_level, DF_OFF(&stream_frame));
|
||||||
|
if (0 == imico_stash_stream_frame(conn, enc_level, packet_in,
|
||||||
|
&stream_frame))
|
||||||
|
return parsed_len;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("Got duplicate CRYPTO frame for enc level #%u -- ignore",
|
LSQ_DEBUG("Got duplicate CRYPTO frame for enc level #%u -- ignore",
|
||||||
|
@ -657,11 +811,19 @@ imico_process_crypto_frame (IMICO_PROC_FRAME_ARGS)
|
||||||
imico_dispatch_stream_events(conn);
|
imico_dispatch_stream_events(conn);
|
||||||
conn->imc_last_in.frame = NULL;
|
conn->imc_last_in.frame = NULL;
|
||||||
|
|
||||||
|
if (DF_ROFF(&stream_frame) < DF_END(&stream_frame))
|
||||||
|
{
|
||||||
|
/* This is an odd condition, but let's handle it just in case */
|
||||||
|
LSQ_DEBUG("New CRYPTO frame on enc level #%u not fully read -- stash",
|
||||||
|
enc_level);
|
||||||
|
if (0 != imico_stash_stream_frame(conn, enc_level, packet_in,
|
||||||
|
&stream_frame))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (enc_level == ENC_LEV_CLEAR && stream_frame.data_frame.df_offset == 0
|
|
||||||
/* Assume that we have ClientHello at offset zero and that it has
|
if (enc_level == ENC_LEV_CLEAR
|
||||||
* transport parameters.
|
&& imico_chlo_has_been_consumed(conn)
|
||||||
*/
|
|
||||||
&& (conn->imc_flags & (IMC_ENC_SESS_INITED|IMC_HAVE_TP))
|
&& (conn->imc_flags & (IMC_ENC_SESS_INITED|IMC_HAVE_TP))
|
||||||
== IMC_ENC_SESS_INITED)
|
== IMC_ENC_SESS_INITED)
|
||||||
{
|
{
|
||||||
|
@ -1452,6 +1614,7 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
||||||
return TICK_CLOSE;
|
return TICK_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (conn->imc_flags &
|
if (conn->imc_flags &
|
||||||
(IMC_QUEUED_ACK_INIT|IMC_QUEUED_ACK_HSK|IMC_QUEUED_ACK_APP))
|
(IMC_QUEUED_ACK_INIT|IMC_QUEUED_ACK_HSK|IMC_QUEUED_ACK_APP))
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,7 @@ struct ietf_mini_conn
|
||||||
} imc_last_in;
|
} imc_last_in;
|
||||||
TAILQ_HEAD(, lsquic_packet_in) imc_app_packets;
|
TAILQ_HEAD(, lsquic_packet_in) imc_app_packets;
|
||||||
TAILQ_HEAD(, lsquic_packet_out) imc_packets_out;
|
TAILQ_HEAD(, lsquic_packet_out) imc_packets_out;
|
||||||
|
TAILQ_HEAD(, stream_frame) imc_crypto_frames;
|
||||||
packno_set_t imc_sent_packnos;
|
packno_set_t imc_sent_packnos;
|
||||||
packno_set_t imc_recvd_packnos[N_PNS];
|
packno_set_t imc_recvd_packnos[N_PNS];
|
||||||
packno_set_t imc_acked_packnos[N_PNS];
|
packno_set_t imc_acked_packnos[N_PNS];
|
||||||
|
@ -72,6 +73,11 @@ struct ietf_mini_conn
|
||||||
unsigned imc_error_code;
|
unsigned imc_error_code;
|
||||||
unsigned imc_bytes_in;
|
unsigned imc_bytes_in;
|
||||||
unsigned imc_bytes_out;
|
unsigned imc_bytes_out;
|
||||||
|
unsigned short imc_crypto_frames_sz;
|
||||||
|
/* We need to read in the length of ClientHello to check when we have fed
|
||||||
|
* it to the crypto layer.
|
||||||
|
*/
|
||||||
|
unsigned short imc_ch_len;
|
||||||
unsigned char imc_next_packno;
|
unsigned char imc_next_packno;
|
||||||
unsigned char imc_hsk_count;
|
unsigned char imc_hsk_count;
|
||||||
/* We don't send more than eight in the first flight, and so it's OK to
|
/* We don't send more than eight in the first flight, and so it's OK to
|
||||||
|
@ -85,9 +91,22 @@ struct ietf_mini_conn
|
||||||
uint8_t imc_ecn_counts_out[N_PNS][4];
|
uint8_t imc_ecn_counts_out[N_PNS][4];
|
||||||
uint8_t imc_incoming_ecn;
|
uint8_t imc_incoming_ecn;
|
||||||
uint8_t imc_tls_alert;
|
uint8_t imc_tls_alert;
|
||||||
|
#define IMICO_MAX_STASHED_FRAMES 10u
|
||||||
|
unsigned char imc_n_crypto_frames;
|
||||||
struct network_path imc_path;
|
struct network_path imc_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* [draft-ietf-quic-transport-24] Section 7.4
|
||||||
|
*
|
||||||
|
" Implementations MUST support buffering at least 4096 bytes of data
|
||||||
|
" received in CRYPTO frames out of order. Endpoints MAY choose to
|
||||||
|
" allow more data to be buffered during the handshake. A larger limit
|
||||||
|
" during the handshake could allow for larger keys or credentials to be
|
||||||
|
" exchanged. An endpoint's buffer size does not need to remain
|
||||||
|
" constant during the life of the connection.
|
||||||
|
*/
|
||||||
|
#define IMICO_MAX_BUFFERED_CRYPTO (6u * 1024u)
|
||||||
|
|
||||||
struct lsquic_conn *
|
struct lsquic_conn *
|
||||||
lsquic_mini_conn_ietf_new (struct lsquic_engine_public *,
|
lsquic_mini_conn_ietf_new (struct lsquic_engine_public *,
|
||||||
const struct lsquic_packet_in *,
|
const struct lsquic_packet_in *,
|
||||||
|
|
|
@ -209,9 +209,10 @@ extern const char *const lsquic_pns2str[];
|
||||||
| QUIC_FTBIT_NEW_TOKEN \
|
| QUIC_FTBIT_NEW_TOKEN \
|
||||||
| QUIC_FTBIT_CRYPTO )
|
| QUIC_FTBIT_CRYPTO )
|
||||||
|
|
||||||
/* [draft-ietf-quic-transport-20] Section 13.1.1 */
|
/* [draft-ietf-quic-transport-24] Section 1.2 */
|
||||||
#define IQUIC_FRAME_ACKABLE_MASK ( \
|
#define IQUIC_FRAME_ACKABLE_MASK ( \
|
||||||
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_ACK|QUIC_FTBIT_PADDING))
|
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_ACK|QUIC_FTBIT_PADDING\
|
||||||
|
|QUIC_FTBIT_CONNECTION_CLOSE))
|
||||||
|
|
||||||
/* [draft-ietf-quic-transport-20], Section 13.2 */
|
/* [draft-ietf-quic-transport-20], Section 13.2 */
|
||||||
/* We bend some rules and retransmit BLOCKED, MAX_DATA, MAX_STREAM_DATA,
|
/* We bend some rules and retransmit BLOCKED, MAX_DATA, MAX_STREAM_DATA,
|
||||||
|
|
|
@ -366,7 +366,7 @@ lsquic_packet_out_ack_streams (lsquic_packet_out_t *packet_out)
|
||||||
static int
|
static int
|
||||||
split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
||||||
unsigned n_srecs)
|
unsigned n_srecs, enum quic_frame_type frame_type)
|
||||||
{
|
{
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
|
memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||||
packet_out->po_data + srec->sr_off, srec->sr_len);
|
packet_out->po_data + srec->sr_off, srec->sr_len);
|
||||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||||
srec->sr_stream, QUIC_FRAME_STREAM,
|
srec->sr_stream, frame_type,
|
||||||
new_packet_out->po_data_sz, srec->sr_len))
|
new_packet_out->po_data_sz, srec->sr_len))
|
||||||
return -1;
|
return -1;
|
||||||
srec->sr_frame_type = 0;
|
srec->sr_frame_type = 0;
|
||||||
|
@ -394,7 +394,7 @@ split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
static int
|
static int
|
||||||
move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
||||||
unsigned n_srecs, unsigned max_idx)
|
unsigned n_srecs, unsigned max_idx, enum quic_frame_type frame_type)
|
||||||
{
|
{
|
||||||
unsigned n;
|
unsigned n;
|
||||||
struct stream_rec *const max_srec = srecs[max_idx];
|
struct stream_rec *const max_srec = srecs[max_idx];
|
||||||
|
@ -405,7 +405,7 @@ move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
packet_out->po_data + max_srec->sr_off + max_srec->sr_len,
|
packet_out->po_data + max_srec->sr_off + max_srec->sr_len,
|
||||||
packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len);
|
packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len);
|
||||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||||
max_srec->sr_stream, QUIC_FRAME_STREAM,
|
max_srec->sr_stream, frame_type,
|
||||||
new_packet_out->po_data_sz, max_srec->sr_len))
|
new_packet_out->po_data_sz, max_srec->sr_len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -448,7 +448,7 @@ split_reader_size (void *ctx)
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
split_reader_read (void *ctx, void *buf, size_t len, int *fin)
|
split_stream_reader_read (void *ctx, void *buf, size_t len, int *fin)
|
||||||
{
|
{
|
||||||
struct split_reader_ctx *const reader_ctx = ctx;
|
struct split_reader_ctx *const reader_ctx = ctx;
|
||||||
if (len > reader_ctx->len - reader_ctx->off)
|
if (len > reader_ctx->len - reader_ctx->off)
|
||||||
|
@ -460,10 +460,23 @@ split_reader_read (void *ctx, void *buf, size_t len, int *fin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
split_crypto_reader_read (void *ctx, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct split_reader_ctx *const reader_ctx = ctx;
|
||||||
|
if (len > reader_ctx->len - reader_ctx->off)
|
||||||
|
len = reader_ctx->len - reader_ctx->off;
|
||||||
|
memcpy(buf, reader_ctx->buf, len);
|
||||||
|
reader_ctx->off += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf,
|
lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf,
|
||||||
struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx)
|
struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx,
|
||||||
|
enum quic_frame_type frame_type)
|
||||||
{
|
{
|
||||||
struct stream_rec *const max_srec = srecs[max_idx];
|
struct stream_rec *const max_srec = srecs[max_idx];
|
||||||
struct stream_frame frame;
|
struct stream_frame frame;
|
||||||
|
@ -471,8 +484,12 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
unsigned n;
|
unsigned n;
|
||||||
struct split_reader_ctx reader_ctx;
|
struct split_reader_ctx reader_ctx;
|
||||||
|
|
||||||
len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off,
|
if (frame_type == QUIC_FRAME_STREAM)
|
||||||
max_srec->sr_len, &frame);
|
len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off,
|
||||||
|
max_srec->sr_len, &frame);
|
||||||
|
else
|
||||||
|
len = pf->pf_parse_crypto_frame(packet_out->po_data + max_srec->sr_off,
|
||||||
|
max_srec->sr_len, &frame);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not parse own frame");
|
LSQ_ERROR("could not parse own frame");
|
||||||
|
@ -490,19 +507,27 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2;
|
reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2;
|
||||||
reader_ctx.fin = frame.data_frame.df_fin;
|
reader_ctx.fin = frame.data_frame.df_fin;
|
||||||
|
|
||||||
len = pf->pf_gen_stream_frame(
|
if (frame_type == QUIC_FRAME_STREAM)
|
||||||
|
len = pf->pf_gen_stream_frame(
|
||||||
new_packet_out->po_data + new_packet_out->po_data_sz,
|
new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(new_packet_out), frame.stream_id,
|
lsquic_packet_out_avail(new_packet_out), frame.stream_id,
|
||||||
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
||||||
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
||||||
split_reader_read, &reader_ctx);
|
split_stream_reader_read, &reader_ctx);
|
||||||
|
else
|
||||||
|
len = pf->pf_gen_crypto_frame(
|
||||||
|
new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||||
|
lsquic_packet_out_avail(new_packet_out),
|
||||||
|
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
||||||
|
split_reader_size(&reader_ctx),
|
||||||
|
split_crypto_reader_read, &reader_ctx);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not generate new frame 1");
|
LSQ_ERROR("could not generate new frame 1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||||
max_srec->sr_stream, QUIC_FRAME_STREAM,
|
max_srec->sr_stream, max_srec->sr_frame_type,
|
||||||
new_packet_out->po_data_sz, len))
|
new_packet_out->po_data_sz, len))
|
||||||
return -1;
|
return -1;
|
||||||
new_packet_out->po_data_sz += len;
|
new_packet_out->po_data_sz += len;
|
||||||
|
@ -517,11 +542,18 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
reader_ctx.off = 0;
|
reader_ctx.off = 0;
|
||||||
reader_ctx.len = frame.data_frame.df_size / 2;
|
reader_ctx.len = frame.data_frame.df_size / 2;
|
||||||
reader_ctx.fin = 0;
|
reader_ctx.fin = 0;
|
||||||
len = pf->pf_gen_stream_frame(
|
if (frame_type == QUIC_FRAME_STREAM)
|
||||||
|
len = pf->pf_gen_stream_frame(
|
||||||
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
||||||
frame.stream_id, frame.data_frame.df_offset,
|
frame.stream_id, frame.data_frame.df_offset,
|
||||||
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
||||||
split_reader_read, &reader_ctx);
|
split_stream_reader_read, &reader_ctx);
|
||||||
|
else
|
||||||
|
len = pf->pf_gen_crypto_frame(
|
||||||
|
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
||||||
|
frame.data_frame.df_offset,
|
||||||
|
split_reader_size(&reader_ctx),
|
||||||
|
split_crypto_reader_read, &reader_ctx);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not generate new frame 2");
|
LSQ_ERROR("could not generate new frame 2");
|
||||||
|
@ -540,7 +572,7 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
static void
|
static void
|
||||||
verify_srecs (lsquic_packet_out_t *packet_out)
|
verify_srecs (lsquic_packet_out_t *packet_out, enum quic_frame_type frame_type)
|
||||||
{
|
{
|
||||||
struct packet_out_srec_iter posi;
|
struct packet_out_srec_iter posi;
|
||||||
const struct stream_rec *srec;
|
const struct stream_rec *srec;
|
||||||
|
@ -553,7 +585,7 @@ verify_srecs (lsquic_packet_out_t *packet_out)
|
||||||
for ( ; srec; srec = posi_next(&posi))
|
for ( ; srec; srec = posi_next(&posi))
|
||||||
{
|
{
|
||||||
assert(srec->sr_off == off);
|
assert(srec->sr_off == off);
|
||||||
assert(srec->sr_frame_type == QUIC_FRAME_STREAM);
|
assert(srec->sr_frame_type == frame_type);
|
||||||
off += srec->sr_len;
|
off += srec->sr_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,15 +605,21 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
struct stream_rec *srec;
|
struct stream_rec *srec;
|
||||||
unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
|
unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
|
||||||
unsigned n_srecs, max_idx, n, nbytes;
|
unsigned n_srecs, max_idx, n, nbytes;
|
||||||
|
enum quic_frame_type frame_type;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned short frame_sum = 0;
|
unsigned short frame_sum = 0;
|
||||||
#endif
|
#endif
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
/* We only split buffered packets; buffered packets contain only STREAM
|
/* We only split buffered packets or initial packets with CRYPTO frames.
|
||||||
* frames:
|
* Either contain just one frame type: STREAM or CRYPTO.
|
||||||
*/
|
*/
|
||||||
assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM));
|
assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM)
|
||||||
|
|| packet_out->po_frame_types == (1 << QUIC_FRAME_CRYPTO));
|
||||||
|
if (packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||||
|
frame_type = QUIC_FRAME_STREAM;
|
||||||
|
else
|
||||||
|
frame_type = QUIC_FRAME_CRYPTO;
|
||||||
|
|
||||||
n_srecs = 0;
|
n_srecs = 0;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -589,8 +627,8 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
#endif
|
#endif
|
||||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||||
{
|
{
|
||||||
/* We only expect references to STREAM frames (buffered packets): */
|
assert(srec->sr_frame_type == QUIC_FRAME_STREAM
|
||||||
assert(srec->sr_frame_type == QUIC_FRAME_STREAM);
|
|| srec->sr_frame_type == QUIC_FRAME_CRYPTO);
|
||||||
if (n_srecs >= n_srecs_alloced)
|
if (n_srecs >= n_srecs_alloced)
|
||||||
{
|
{
|
||||||
n_srecs_alloced *= 2;
|
n_srecs_alloced *= 2;
|
||||||
|
@ -636,7 +674,7 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
if (nbytes >= excess_bytes)
|
if (nbytes >= excess_bytes)
|
||||||
{
|
{
|
||||||
rv = split_off_last_frames(mm, packet_out, new_packet_out,
|
rv = split_off_last_frames(mm, packet_out, new_packet_out,
|
||||||
srecs + n + 1, n_srecs - n - 1);
|
srecs + n + 1, n_srecs - n - 1, frame_type);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,7 +686,7 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
if (nbytes >= excess_bytes)
|
if (nbytes >= excess_bytes)
|
||||||
{
|
{
|
||||||
rv = move_largest_frame(mm, packet_out, new_packet_out, srecs,
|
rv = move_largest_frame(mm, packet_out, new_packet_out, srecs,
|
||||||
n_srecs, max_idx);
|
n_srecs, max_idx, frame_type);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,17 +695,17 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
* the only frame) in two.
|
* the only frame) in two.
|
||||||
*/
|
*/
|
||||||
rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs,
|
rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs,
|
||||||
n_srecs, max_idx);
|
n_srecs, max_idx, frame_type);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (srecs != local_arr)
|
if (srecs != local_arr)
|
||||||
free(srecs);
|
free(srecs);
|
||||||
if (0 == rv)
|
if (0 == rv)
|
||||||
{
|
{
|
||||||
new_packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
|
new_packet_out->po_frame_types |= 1 << frame_type;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
verify_srecs(packet_out);
|
verify_srecs(packet_out, frame_type);
|
||||||
verify_srecs(new_packet_out);
|
verify_srecs(new_packet_out, frame_type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -245,6 +245,11 @@ struct parse_funcs
|
||||||
(*pf_gen_max_data_frame) (unsigned char *, size_t, uint64_t);
|
(*pf_gen_max_data_frame) (unsigned char *, size_t, uint64_t);
|
||||||
unsigned
|
unsigned
|
||||||
(*pf_max_data_frame_size) (uint64_t);
|
(*pf_max_data_frame_size) (uint64_t);
|
||||||
|
/*
|
||||||
|
* Returns number of bytes parsed on success or negative value on error:
|
||||||
|
* -1 Out of input buffer
|
||||||
|
* -2 Invalid CID length value
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
(*pf_parse_new_conn_id) (const unsigned char *, size_t, uint64_t *,
|
(*pf_parse_new_conn_id) (const unsigned char *, size_t, uint64_t *,
|
||||||
uint64_t *, lsquic_cid_t *, const unsigned char **);
|
uint64_t *, lsquic_cid_t *, const unsigned char **);
|
||||||
|
|
|
@ -1272,6 +1272,8 @@ ietf_v1_parse_new_conn_id (const unsigned char *buf, size_t len,
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
cid_len = *p++;
|
cid_len = *p++;
|
||||||
|
if (cid_len == 0 || cid_len > MAX_CID_LEN)
|
||||||
|
return -2;
|
||||||
|
|
||||||
if ((unsigned) (end - p) < cid_len + IQUIC_SRESET_TOKEN_SZ)
|
if ((unsigned) (end - p) < cid_len + IQUIC_SRESET_TOKEN_SZ)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -267,41 +267,24 @@ put_req (struct pr_queue *prq, struct packet_req *req)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
const struct lsquic_packet_in *packet_in, void *peer_ctx,
|
unsigned flags, enum lsquic_version version, unsigned short data_sz,
|
||||||
const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
|
const lsquic_cid_t *dcid, const lsquic_cid_t *scid, void *peer_ctx,
|
||||||
|
const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
|
||||||
{
|
{
|
||||||
struct packet_req *req;
|
struct packet_req *req;
|
||||||
lsquic_ver_tag_t ver_tag;
|
|
||||||
enum lsquic_version version;
|
|
||||||
enum pr_flags flags;
|
|
||||||
unsigned max, size, rand;
|
unsigned max, size, rand;
|
||||||
|
|
||||||
if (packet_in->pi_flags & PI_GQUIC)
|
|
||||||
flags = PR_GQUIC;
|
|
||||||
else
|
|
||||||
flags = 0;
|
|
||||||
|
|
||||||
if (packet_in->pi_quic_ver)
|
|
||||||
{
|
|
||||||
memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
|
|
||||||
sizeof(ver_tag));
|
|
||||||
version = lsquic_tag2ver(ver_tag);
|
|
||||||
}
|
|
||||||
else /* Got to set it to something sensible... */
|
|
||||||
version = LSQVER_ID23;
|
|
||||||
|
|
||||||
if (type == PACKET_REQ_PUBRES && !(flags & PR_GQUIC))
|
if (type == PACKET_REQ_PUBRES && !(flags & PR_GQUIC))
|
||||||
{
|
{
|
||||||
if (packet_in->pi_data_sz <= IQUIC_MIN_SRST_SIZE)
|
if (data_sz <= IQUIC_MIN_SRST_SIZE)
|
||||||
{
|
{
|
||||||
LSQ_DEBUGC("not scheduling public reset: incoming packet for CID "
|
LSQ_DEBUGC("not scheduling public reset: incoming packet for CID "
|
||||||
"%"CID_FMT" too small: %hu bytes",
|
"%"CID_FMT" too small: %hu bytes", CID_BITS(dcid), data_sz);
|
||||||
CID_BITS(&packet_in->pi_dcid), packet_in->pi_data_sz);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Use a random stateless reset size */
|
/* Use a random stateless reset size */
|
||||||
max = MIN(IQUIC_MAX_SRST_SIZE, packet_in->pi_data_sz - 1u);
|
max = MIN(IQUIC_MAX_SRST_SIZE, data_sz - 1u);
|
||||||
if (max > IQUIC_MIN_SRST_SIZE)
|
if (max > IQUIC_MIN_SRST_SIZE)
|
||||||
{
|
{
|
||||||
rand = get_rand_byte(prq);
|
rand = get_rand_byte(prq);
|
||||||
|
@ -310,7 +293,7 @@ prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
else
|
else
|
||||||
size = IQUIC_MIN_SRST_SIZE;
|
size = IQUIC_MIN_SRST_SIZE;
|
||||||
LSQ_DEBUGC("selected %u-byte reset size for CID %"CID_FMT
|
LSQ_DEBUGC("selected %u-byte reset size for CID %"CID_FMT
|
||||||
" (range is [%u, %u])", size, CID_BITS(&packet_in->pi_dcid),
|
" (range is [%u, %u])", size, CID_BITS(dcid),
|
||||||
IQUIC_MIN_SRST_SIZE, max);
|
IQUIC_MIN_SRST_SIZE, max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -324,7 +307,7 @@ prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
}
|
}
|
||||||
|
|
||||||
req->pr_type = type;
|
req->pr_type = type;
|
||||||
req->pr_dcid = packet_in->pi_dcid;
|
req->pr_dcid = *dcid;
|
||||||
if (lsquic_hash_find(prq->prq_reqs_hash, req, sizeof(req)))
|
if (lsquic_hash_find(prq->prq_reqs_hash, req, sizeof(req)))
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("request for this DCID and type already exists");
|
LSQ_DEBUG("request for this DCID and type already exists");
|
||||||
|
@ -344,7 +327,7 @@ prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
req->pr_flags = flags;
|
req->pr_flags = flags;
|
||||||
req->pr_rst_sz = size;
|
req->pr_rst_sz = size;
|
||||||
req->pr_version = version;
|
req->pr_version = version;
|
||||||
lsquic_scid_from_packet_in(packet_in, &req->pr_scid);
|
req->pr_scid = *scid;
|
||||||
req->pr_path.np_peer_ctx = peer_ctx;
|
req->pr_path.np_peer_ctx = peer_ctx;
|
||||||
memcpy(NP_LOCAL_SA(&req->pr_path), local_addr,
|
memcpy(NP_LOCAL_SA(&req->pr_path), local_addr,
|
||||||
sizeof(req->pr_path.np_local_addr));
|
sizeof(req->pr_path.np_local_addr));
|
||||||
|
@ -357,6 +340,36 @@ prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
||||||
|
const struct lsquic_packet_in *packet_in, void *peer_ctx,
|
||||||
|
const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
|
||||||
|
{
|
||||||
|
lsquic_ver_tag_t ver_tag;
|
||||||
|
enum lsquic_version version;
|
||||||
|
enum pr_flags flags;
|
||||||
|
lsquic_cid_t scid;
|
||||||
|
|
||||||
|
if (packet_in->pi_flags & PI_GQUIC)
|
||||||
|
flags = PR_GQUIC;
|
||||||
|
else
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
if (packet_in->pi_quic_ver)
|
||||||
|
{
|
||||||
|
memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
|
||||||
|
sizeof(ver_tag));
|
||||||
|
version = lsquic_tag2ver(ver_tag);
|
||||||
|
}
|
||||||
|
else /* Got to set it to something sensible... */
|
||||||
|
version = LSQVER_ID24;
|
||||||
|
|
||||||
|
lsquic_scid_from_packet_in(packet_in, &scid);
|
||||||
|
return lsquic_prq_new_req(prq, type, flags, version, packet_in->pi_data_sz,
|
||||||
|
&packet_in->pi_dcid, &scid, peer_ctx, local_addr, peer_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
max_bufsz (const struct pr_queue *prq)
|
max_bufsz (const struct pr_queue *prq)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1654,7 +1654,7 @@ lsquic_send_ctl_have_outgoing_retx_frames (const lsquic_send_ctl_t *ctl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_ctl_set_packet_out_token (const struct lsquic_send_ctl *ctl,
|
send_ctl_set_packet_out_token (const struct lsquic_send_ctl *ctl,
|
||||||
struct lsquic_packet_out *packet_out)
|
struct lsquic_packet_out *packet_out)
|
||||||
{
|
{
|
||||||
|
@ -1664,7 +1664,7 @@ send_ctl_set_packet_out_token (const struct lsquic_send_ctl *ctl,
|
||||||
if (!token)
|
if (!token)
|
||||||
{
|
{
|
||||||
LSQ_WARN("malloc failed: cannot set initial token");
|
LSQ_WARN("malloc failed: cannot set initial token");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(token, ctl->sc_token, ctl->sc_token_sz);
|
memcpy(token, ctl->sc_token, ctl->sc_token_sz);
|
||||||
|
@ -1672,6 +1672,7 @@ send_ctl_set_packet_out_token (const struct lsquic_send_ctl *ctl,
|
||||||
packet_out->po_token_len = ctl->sc_token_sz;
|
packet_out->po_token_len = ctl->sc_token_sz;
|
||||||
packet_out->po_flags |= PO_NONCE;
|
packet_out->po_flags |= PO_NONCE;
|
||||||
LSQ_DEBUG("set initial token on packet");
|
LSQ_DEBUG("set initial token on packet");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1706,7 +1707,7 @@ send_ctl_allocate_packet (struct lsquic_send_ctl *ctl, enum packno_bits bits,
|
||||||
{
|
{
|
||||||
packet_out->po_header_type = HETY_INITIAL;
|
packet_out->po_header_type = HETY_INITIAL;
|
||||||
if (ctl->sc_token)
|
if (ctl->sc_token)
|
||||||
send_ctl_set_packet_out_token(ctl, packet_out);
|
(void) send_ctl_set_packet_out_token(ctl, packet_out);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
packet_out->po_header_type = HETY_HANDSHAKE;
|
packet_out->po_header_type = HETY_HANDSHAKE;
|
||||||
|
@ -2553,11 +2554,31 @@ lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *ctl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
strip_trailing_padding (struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
struct packet_out_srec_iter posi;
|
||||||
|
const struct stream_rec *srec;
|
||||||
|
unsigned off;
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||||
|
off = srec->sr_off + srec->sr_len;
|
||||||
|
|
||||||
|
assert(off);
|
||||||
|
|
||||||
|
packet_out->po_data_sz = off;
|
||||||
|
packet_out->po_frame_types &= ~QUIC_FTBIT_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_retry (struct lsquic_send_ctl *ctl,
|
lsquic_send_ctl_retry (struct lsquic_send_ctl *ctl,
|
||||||
const unsigned char *token, size_t token_sz, int cidlen_diff)
|
const unsigned char *token, size_t token_sz)
|
||||||
{
|
{
|
||||||
struct lsquic_packet_out *packet_out;
|
struct lsquic_packet_out *packet_out, *next, *new_packet_out;
|
||||||
|
struct lsquic_conn *const lconn = ctl->sc_conn_pub->lconn;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
if (token_sz >= 1ull << (sizeof(packet_out->po_token_len) * 8))
|
if (token_sz >= 1ull << (sizeof(packet_out->po_token_len) * 8))
|
||||||
{
|
{
|
||||||
|
@ -2565,14 +2586,6 @@ lsquic_send_ctl_retry (struct lsquic_send_ctl *ctl,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_ctl_expire(ctl, PNS_INIT, EXFI_ALL);
|
|
||||||
packet_out = TAILQ_FIRST(&ctl->sc_lost_packets);
|
|
||||||
if (!(packet_out && HETY_INITIAL == packet_out->po_header_type))
|
|
||||||
{
|
|
||||||
LSQ_INFO("cannot find initial packet to add token to");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
++ctl->sc_retry_count;
|
++ctl->sc_retry_count;
|
||||||
if (ctl->sc_retry_count > 3)
|
if (ctl->sc_retry_count > 3)
|
||||||
{
|
{
|
||||||
|
@ -2580,26 +2593,57 @@ lsquic_send_ctl_retry (struct lsquic_send_ctl *ctl,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_ctl_expire(ctl, PNS_INIT, EXFI_ALL);
|
||||||
|
|
||||||
if (0 != lsquic_send_ctl_set_token(ctl, token, token_sz))
|
if (0 != lsquic_send_ctl_set_token(ctl, token, token_sz))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (packet_out->po_nonce)
|
for (packet_out = TAILQ_FIRST(&ctl->sc_lost_packets); packet_out; packet_out = next)
|
||||||
free(packet_out->po_nonce);
|
|
||||||
|
|
||||||
packet_out->po_nonce = malloc(token_sz);
|
|
||||||
if (!packet_out->po_nonce)
|
|
||||||
{
|
{
|
||||||
LSQ_WARN("%s: malloc failed", __func__);
|
next = TAILQ_NEXT(packet_out, po_next);
|
||||||
return -1;
|
if (HETY_INITIAL != packet_out->po_header_type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (packet_out->po_nonce)
|
||||||
|
free(packet_out->po_nonce);
|
||||||
|
|
||||||
|
if (0 != send_ctl_set_packet_out_token(ctl, packet_out))
|
||||||
|
{
|
||||||
|
LSQ_INFO("cannot set out token on packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet_out->po_frame_types & QUIC_FTBIT_PADDING)
|
||||||
|
strip_trailing_padding(packet_out);
|
||||||
|
|
||||||
|
sz = lconn->cn_pf->pf_packout_size(lconn, packet_out);
|
||||||
|
if (sz > 1200)
|
||||||
|
{
|
||||||
|
const enum packno_bits bits = lsquic_send_ctl_calc_packno_bits(ctl);
|
||||||
|
new_packet_out = send_ctl_allocate_packet(ctl, bits, 0, PNS_INIT,
|
||||||
|
packet_out->po_path);
|
||||||
|
if (!new_packet_out)
|
||||||
|
return -1;
|
||||||
|
if (0 == lsquic_packet_out_split_in_two(&ctl->sc_enpub->enp_mm,
|
||||||
|
packet_out, new_packet_out,
|
||||||
|
ctl->sc_conn_pub->lconn->cn_pf, sz - 1200))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("split lost packet %"PRIu64" into two",
|
||||||
|
packet_out->po_packno);
|
||||||
|
lsquic_packet_out_set_packno_bits(packet_out, bits);
|
||||||
|
TAILQ_INSERT_AFTER(&ctl->sc_lost_packets, packet_out,
|
||||||
|
new_packet_out, po_next);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("could not split lost packet into two");
|
||||||
|
send_ctl_destroy_packet(ctl, new_packet_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
memcpy(packet_out->po_nonce, token, token_sz);
|
|
||||||
packet_out->po_flags |= PO_NONCE;
|
|
||||||
packet_out->po_token_len = token_sz;
|
|
||||||
packet_out->po_data_sz -= token_sz;
|
|
||||||
if (cidlen_diff > 0)
|
|
||||||
packet_out->po_data_sz += cidlen_diff;
|
|
||||||
else if (cidlen_diff < 0)
|
|
||||||
packet_out->po_data_sz -= -cidlen_diff;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,8 +335,7 @@ void
|
||||||
lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *);
|
lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *);
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_retry (struct lsquic_send_ctl *, const unsigned char *,
|
lsquic_send_ctl_retry (struct lsquic_send_ctl *, const unsigned char *, size_t);
|
||||||
size_t, int);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_set_token (struct lsquic_send_ctl *,
|
lsquic_send_ctl_set_token (struct lsquic_send_ctl *,
|
||||||
|
|
|
@ -111,6 +111,10 @@ lsquic_tp_encode (const struct transport_params *params,
|
||||||
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
|
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
|
||||||
need += 4 + preferred_address_size(params);
|
need += 4 + preferred_address_size(params);
|
||||||
}
|
}
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
else if (params->tp_flags & TRAPA_QUANTUM_READY)
|
||||||
|
need += 4 + QUANTUM_READY_SZ;
|
||||||
|
#endif
|
||||||
|
|
||||||
for (tpi = 0; tpi <= MAX_TPI; ++tpi)
|
for (tpi = 0; tpi <= MAX_TPI; ++tpi)
|
||||||
if ((NUMERIC_TRANS_PARAMS & (1 << tpi))
|
if ((NUMERIC_TRANS_PARAMS & (1 << tpi))
|
||||||
|
@ -252,6 +256,16 @@ lsquic_tp_encode (const struct transport_params *params,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
if (params->tp_flags & TRAPA_QUANTUM_READY)
|
||||||
|
{
|
||||||
|
WRITE_UINT_TO_P(TPI_QUANTUM_READINESS, 16);
|
||||||
|
WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16);
|
||||||
|
memset(p, 'Q', QUANTUM_READY_SZ);
|
||||||
|
p += QUANTUM_READY_SZ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(buf + need == p);
|
assert(buf + need == p);
|
||||||
return (int) (p - buf);
|
return (int) (p - buf);
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,12 @@ enum trapa_flags
|
||||||
TRAPA_PREFADDR_IPv4 = 1 << 2, /* Preferred IPv4 address is set */
|
TRAPA_PREFADDR_IPv4 = 1 << 2, /* Preferred IPv4 address is set */
|
||||||
TRAPA_PREFADDR_IPv6 = 1 << 3, /* Preferred IPv6 address is set */
|
TRAPA_PREFADDR_IPv6 = 1 << 3, /* Preferred IPv6 address is set */
|
||||||
TRAPA_ORIGINAL_CID = 1 << 4, /* Original CID is set */
|
TRAPA_ORIGINAL_CID = 1 << 4, /* Original CID is set */
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
#define QUANTUM_READY_SZ 1200
|
||||||
|
/* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */
|
||||||
|
#define TPI_QUANTUM_READINESS 3127
|
||||||
|
TRAPA_QUANTUM_READY = 1 << 5, /* Include "Quantum Readiness" TP */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct transport_params
|
struct transport_params
|
||||||
|
|
|
@ -15,6 +15,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
|
||||||
[LSQVER_098] = { 'Q', '0', '9', '8', },
|
[LSQVER_098] = { 'Q', '0', '9', '8', },
|
||||||
#endif
|
#endif
|
||||||
[LSQVER_ID23] = { 0xFF, 0, 0, 23, },
|
[LSQVER_ID23] = { 0xFF, 0, 0, 23, },
|
||||||
|
[LSQVER_ID24] = { 0xFF, 0, 0, 24, },
|
||||||
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
|
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
|
||||||
[LSQVER_098] = "Q098",
|
[LSQVER_098] = "Q098",
|
||||||
#endif
|
#endif
|
||||||
[LSQVER_ID23] = "FF000017",
|
[LSQVER_ID23] = "FF000017",
|
||||||
|
[LSQVER_ID24] = "FF000018",
|
||||||
[LSQVER_VERNEG] = "FAFAFAFA",
|
[LSQVER_VERNEG] = "FAFAFAFA",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ static int
|
||||||
select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen,
|
select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen,
|
||||||
const unsigned char *in, unsigned int inlen, void *arg)
|
const unsigned char *in, unsigned int inlen, void *arg)
|
||||||
{
|
{
|
||||||
const unsigned char alpn[] = "\x5h3-23";
|
const unsigned char alpn[] = "\x5h3-23\x5h3-24";
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen,
|
r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen,
|
||||||
|
|
Loading…
Reference in a new issue