Release 2.17.0

- [FEATURE] QUIC and HTTP/3 Internet Draft 29 support.
- [BUGFIX] Check that scheduled packets are also sendable when
  calculating a connection's "tickable" property.
- [BUGFIX] Don't count scheduled packets as in-flight when pacer is
  checked on tick.
- gQUIC: delay calling on_new for pushed stream until headers are
  available.
- Allow nested calls to lsquic_engine_connect().
This commit is contained in:
Dmitri Tikhonov 2020-06-18 09:45:44 -04:00
parent 307ca7fe50
commit 4051ae3a1a
19 changed files with 343 additions and 56 deletions

View file

@ -1,3 +1,14 @@
2020-06-18
- 2.17.0
- [FEATURE] QUIC and HTTP/3 Internet Draft 29 support.
- [BUGFIX] Check that scheduled packets are also sendable when
calculating a connection's "tickable" property.
- [BUGFIX] Don't count scheduled packets as in-flight when pacer is
checked on tick.
- gQUIC: delay calling on_new for pushed stream until headers are
available.
- Allow nested calls to lsquic_engine_connect().
2020-06-15
- 2.16.3
- [OPTIMIZATION] Stash up to two reordered packets in IETF mini conn

View file

@ -21,7 +21,7 @@ static int
select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg)
{
const unsigned char alpn[] = "\x5h3-27\x5h3-28";
const unsigned char alpn[] = "\x5h3-27\x5h3-28\x5h3-29";
int r;
r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen,

View file

@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
author = u'LiteSpeed Technologies'
# The short X.Y version
version = u'2.16'
version = u'2.17'
# The full version, including alpha/beta/rc tags
release = u'2.16.3'
release = u'2.17.0'
# -- General configuration ---------------------------------------------------

View file

@ -24,8 +24,8 @@ extern "C" {
#endif
#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 16
#define LSQUIC_PATCH_VERSION 3
#define LSQUIC_MINOR_VERSION 17
#define LSQUIC_PATCH_VERSION 0
/**
* Engine flags:
@ -86,6 +86,11 @@ enum lsquic_version
*/
LSQVER_ID28,
/**
* IETF QUIC Draft-29
*/
LSQVER_ID29,
/**
* Special version to trigger version negotiation.
* [draft-ietf-quic-transport-11], Section 3.
@ -114,10 +119,10 @@ enum lsquic_version
#define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043)
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
| (1 << LSQVER_VERNEG))
| (1 << LSQVER_ID29) | (1 << LSQVER_VERNEG))
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
| (1 << LSQVER_VERNEG))
| (1 << LSQVER_ID29) | (1 << LSQVER_VERNEG))
enum lsquic_hsk_status
{

View file

@ -334,6 +334,7 @@ extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
#define select_esf_common_by_ver(ver) ( \
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID28 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID29 ? &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

@ -73,7 +73,8 @@ static const struct alpn_map {
} s_h3_alpns[] = {
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
{ LSQVER_ID28, (unsigned char *) "\x05h3-28", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-28", },
{ LSQVER_ID29, (unsigned char *) "\x05h3-29", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-29", },
};
struct enc_sess_iquic;
@ -935,7 +936,8 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
hp = &enc_sess->esi_hsk_hps[ENC_LEV_CLEAR];
HKDF_extract(hsk_secret, &hsk_secret_sz, md, cid->idbuf, cid->len,
HSK_SALT, HSK_SALT_SZ);
enc_sess->esi_conn->cn_version < LSQVER_ID29
? HSK_SALT_PRE29 : HSK_SALT, HSK_SALT_SZ);
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
{
LSQ_DEBUG("handshake salt: %s", HEXSTR(HSK_SALT, HSK_SALT_SZ, hexbuf));
@ -1177,6 +1179,13 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
LSQ_INFO("could not set stream method");
return -1;
}
/* TODO: set to transport parameter string instead of the constant string */
if (!SSL_set_quic_early_data_context(enc_sess->esi_ssl,
(unsigned char *) "lsquic", 6))
{
LSQ_INFO("could not set early data context");
return -1;
}
maybe_setup_key_logging(enc_sess);
transpa_len = gen_trans_params(enc_sess, u.trans_params,
@ -1756,7 +1765,7 @@ iquic_esfi_destroy (enc_session_t *enc_session_p)
struct enc_sess_iquic *const enc_sess = enc_session_p;
struct frab_list *fral;
LSQ_DEBUG("iquic_esfi_destroy");
for (fral = enc_sess->esi_frals; fral < enc_sess->esi_frals
+ sizeof(enc_sess->esi_frals) / sizeof(enc_sess->esi_frals[0]);
++fral)
@ -3004,3 +3013,23 @@ const struct lsquic_stream_if lsquic_mini_cry_sm_if =
};
const unsigned char *const lsquic_retry_key_buf[N_IETF_RETRY_VERSIONS] =
{
/* [draft-ietf-quic-tls-25] Section 5.8 */
(unsigned char *)
"\x4d\x32\xec\xdb\x2a\x21\x33\xc8\x41\xe4\x04\x3d\xf2\x7d\x44\x30",
/* [draft-ietf-quic-tls-29] Section 5.8 */
(unsigned char *)
"\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1",
};
const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS] =
{
/* [draft-ietf-quic-tls-25] Section 5.8 */
(unsigned char *) "\x4d\x16\x11\xd0\x55\x13\xa5\x52\xc5\x87\xd5\x75",
/* [draft-ietf-quic-tls-29] Section 5.8 */
(unsigned char *) "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c",
};

View file

@ -135,7 +135,9 @@ force_close_conn (lsquic_engine_t *engine, lsquic_conn_t *conn);
#define ENGINE_CALLS_INCR(e)
#endif
/* Nested calls to LSQUIC are not supported */
/* Nested calls to some LSQUIC functions are not supported. Functions that
* iterate over connections cannot be nested.
*/
#define ENGINE_IN(e) do { \
assert(!((e)->pub.enp_flags & ENPUB_PROC)); \
(e)->pub.enp_flags |= ENPUB_PROC; \
@ -270,7 +272,7 @@ struct lsquic_engine
int last_tick_diff;
#endif
struct crand crand;
EVP_AEAD_CTX retry_aead_ctx;
EVP_AEAD_CTX retry_aead_ctx[N_IETF_RETRY_VERSIONS];
};
@ -483,6 +485,7 @@ lsquic_engine_new (unsigned flags,
{
lsquic_engine_t *engine;
size_t alpn_len;
unsigned i;
char err_buf[100];
if (!api->ea_packets_out)
@ -691,14 +694,17 @@ lsquic_engine_new (unsigned flags,
#if LSQUIC_CONN_STATS
engine->stats_fh = api->ea_stats_fh;
#endif
if (1 != EVP_AEAD_CTX_init(&engine->retry_aead_ctx, EVP_aead_aes_128_gcm(),
IETF_RETRY_KEY_BUF, IETF_RETRY_KEY_SZ, 16, NULL))
{
LSQ_ERROR("could not initialize retry AEAD ctx");
lsquic_engine_destroy(engine);
return NULL;
}
engine->pub.enp_retry_aead_ctx = &engine->retry_aead_ctx;
for (i = 0; i < sizeof(engine->retry_aead_ctx)
/ sizeof(engine->retry_aead_ctx[0]); ++i)
if (1 != EVP_AEAD_CTX_init(&engine->retry_aead_ctx[i],
EVP_aead_aes_128_gcm(), lsquic_retry_key_buf[i],
IETF_RETRY_KEY_SZ, 16, NULL))
{
LSQ_ERROR("could not initialize retry AEAD ctx #%u", i);
lsquic_engine_destroy(engine);
return NULL;
}
engine->pub.enp_retry_aead_ctx = engine->retry_aead_ctx;
LSQ_INFO("instantiated engine");
return engine;
@ -1421,6 +1427,7 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
{
struct lsquic_hash_elem *el;
lsquic_conn_t *conn;
unsigned i;
LSQ_DEBUG("destroying engine");
#ifndef NDEBUG
@ -1515,8 +1522,9 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
#if LSQUIC_COUNT_ENGINE_CALLS
LSQ_NOTICE("number of calls into the engine: %lu", engine->n_engine_calls);
#endif
if (engine->pub.enp_retry_aead_ctx)
EVP_AEAD_CTX_cleanup(engine->pub.enp_retry_aead_ctx);
for (i = 0; i < sizeof(engine->retry_aead_ctx)
/ sizeof(engine->retry_aead_ctx[0]); ++i)
EVP_AEAD_CTX_cleanup(&engine->pub.enp_retry_aead_ctx[i]);
free(engine->pub.enp_alpn);
free(engine);
}
@ -1579,7 +1587,7 @@ lsquic_engine_connect (lsquic_engine_t *engine, enum lsquic_version version,
unsigned flags, versions;
int is_ipv4;
ENGINE_IN(engine);
ENGINE_CALLS_INCR(engine);
if (engine->flags & ENG_SERVER)
{
@ -1650,7 +1658,6 @@ lsquic_engine_connect (lsquic_engine_t *engine, enum lsquic_version version,
lsquic_conn_set_ctx(conn, conn_ctx);
conn->cn_if->ci_client_call_on_new(conn);
end:
ENGINE_OUT(engine);
return conn;
err:
conn = NULL;

View file

@ -4060,7 +4060,7 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
return -1;
}
pushed_stream = new_stream(conn, stream_id, SCF_CALL_ON_NEW);
pushed_stream = new_stream(conn, stream_id, 0);
if (!pushed_stream)
{
LSQ_WARN("cannot create stream: %s", strerror(errno));
@ -4085,6 +4085,7 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
return -1;
}
lsquic_stream_call_on_new(pushed_stream);
return 0;
}
@ -4187,10 +4188,10 @@ full_conn_ci_is_tickable (lsquic_conn_t *lconn)
LSQ_DEBUG("tickable: flags: 0x%X", conn->fc_flags & send_flags);
goto check_can_send;
}
if (lsquic_send_ctl_n_scheduled(&conn->fc_send_ctl) > 0)
if (lsquic_send_ctl_has_sendable(&conn->fc_send_ctl))
{
LSQ_DEBUG("tickable: has scheduled packets");
return 1; /* Don't check can_send */
LSQ_DEBUG("tickable: has sendable packets");
return 1; /* Don't check can_send: already on scheduled queue */
}
if ((conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
&& lsquic_send_ctl_has_buffered(&conn->fc_send_ctl))

View file

@ -410,6 +410,7 @@ struct ietf_full_conn
struct ver_neg
ifcli_ver_neg;
uint64_t ifcli_max_push_id;
uint64_t ifcli_min_goaway_stream_id;
enum {
IFCLI_PUSH_ENABLED = 1 << 0,
IFCLI_HSK_SENT_OR_DEL = 1 << 1,
@ -2889,13 +2890,19 @@ try_to_begin_migration (struct ietf_full_conn *conn,
struct sockaddr_in6 v6;
} sockaddr;
if ((params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
|| !conn->ifc_settings->es_allow_migration)
if (!conn->ifc_settings->es_allow_migration)
{
if (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
return BM_NOT_MIGRATING;
}
if (conn->ifc_conn.cn_version <= LSQVER_ID28 /* Starting with ID-29,
disable_active_migration TP applies only to the time period during
the handshake. Our client does not migrate during the handshake:
this code runs only after handshake has succeeded. */
&& (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION)))
{
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
return BM_NOT_MIGRATING;
}
@ -3547,10 +3554,10 @@ ietf_full_conn_ci_is_tickable (struct lsquic_conn *lconn)
LSQ_DEBUG("tickable: send flags: 0x%X", conn->ifc_send_flags);
goto check_can_send;
}
if (lsquic_send_ctl_n_scheduled(&conn->ifc_send_ctl) > 0)
if (lsquic_send_ctl_has_sendable(&conn->ifc_send_ctl))
{
LSQ_DEBUG("tickable: has scheduled packets");
return 1; /* Don't check can_send */
LSQ_DEBUG("tickable: has sendable packets");
return 1; /* Don't check can_send: already on scheduled queue */
}
if (conn->ifc_conn.cn_flags & LSCONN_SEND_BLOCKED)
{
@ -6046,6 +6053,7 @@ verify_retry_packet (struct ietf_full_conn *conn,
{
unsigned char *pseudo_packet;
size_t out_len, ad_len;
unsigned ret_ver;
int verified;
if (1 + CUR_DCID(conn)->len + packet_in->pi_data_sz > 0x1000)
@ -6070,11 +6078,13 @@ verify_retry_packet (struct ietf_full_conn *conn,
memcpy(pseudo_packet + 1 + CUR_DCID(conn)->len, packet_in->pi_data,
packet_in->pi_data_sz);
ret_ver = lsquic_version_2_retryver(conn->ifc_conn.cn_version);
out_len = 0;
ad_len = 1 + CUR_DCID(conn)->len + packet_in->pi_data_sz - 16;
verified = 1 == EVP_AEAD_CTX_open(conn->ifc_enpub->enp_retry_aead_ctx,
verified = 1 == EVP_AEAD_CTX_open(
&conn->ifc_enpub->enp_retry_aead_ctx[ret_ver],
pseudo_packet + ad_len, &out_len, out_len,
IETF_RETRY_NONCE_BUF, IETF_RETRY_NONCE_SZ,
lsquic_retry_nonce_buf[ret_ver], IETF_RETRY_NONCE_SZ,
pseudo_packet + ad_len, 16, pseudo_packet, ad_len)
&& out_len == 0;
@ -7472,7 +7482,7 @@ on_setting (void *ctx, uint64_t setting_id, uint64_t value)
static void
on_goaway_server (void *ctx, uint64_t stream_id)
on_goaway_server_27 (void *ctx, uint64_t stream_id)
{
struct ietf_full_conn *const conn = ctx;
ABORT_QUIETLY(1, HEC_FRAME_UNEXPECTED,
@ -7481,7 +7491,7 @@ on_goaway_server (void *ctx, uint64_t stream_id)
static void
on_goaway (void *ctx, uint64_t stream_id)
on_goaway_client_28 (void *ctx, uint64_t stream_id)
{
struct ietf_full_conn *const conn = ctx;
struct lsquic_stream *stream;
@ -7520,6 +7530,68 @@ on_goaway (void *ctx, uint64_t stream_id)
}
static void
on_goaway_client (void *ctx, uint64_t stream_id)
{
struct ietf_full_conn *const conn = ctx;
struct lsquic_stream *stream;
struct lsquic_hash_elem *el;
enum stream_id_type sit;
sit = stream_id & SIT_MASK;
if (sit != SIT_BIDI_CLIENT)
{
ABORT_QUIETLY(1, HEC_ID_ERROR,
"stream ID %"PRIu64" in GOAWAY frame", stream_id);
return;
}
LSQ_DEBUG("received GOAWAY frame, last good stream ID: %"PRIu64, stream_id);
if (conn->ifc_conn.cn_flags & LSCONN_PEER_GOING_AWAY)
{
if (stream_id == conn->ifc_u.cli.ifcli_min_goaway_stream_id)
{
LSQ_DEBUG("ignore duplicate GOAWAY frame");
return;
}
if (stream_id > conn->ifc_u.cli.ifcli_min_goaway_stream_id)
{
ABORT_QUIETLY(1, HEC_ID_ERROR,
"stream ID %"PRIu64" is larger than one already seen in a "
"previous GOAWAY frame, %"PRIu64, stream_id,
conn->ifc_u.cli.ifcli_min_goaway_stream_id);
return;
}
}
else
{
conn->ifc_u.cli.ifcli_min_goaway_stream_id = stream_id;
conn->ifc_conn.cn_flags |= LSCONN_PEER_GOING_AWAY;
if (conn->ifc_enpub->enp_stream_if->on_goaway_received)
conn->ifc_enpub->enp_stream_if->on_goaway_received(&conn->ifc_conn);
}
for (el = lsquic_hash_first(conn->ifc_pub.all_streams); el;
el = lsquic_hash_next(conn->ifc_pub.all_streams))
{
stream = lsquic_hashelem_getdata(el);
if (stream->id >= stream_id
&& (stream->id & SIT_MASK) == SIT_BIDI_CLIENT)
{
lsquic_stream_received_goaway(stream);
}
}
}
static void
on_goaway_server (void *ctx, uint64_t max_push_id)
{
/* TODO: cancel pushes? */
}
static void
on_unexpected_frame (void *ctx, uint64_t frame_type)
{
@ -7529,7 +7601,49 @@ on_unexpected_frame (void *ctx, uint64_t frame_type)
}
static const struct hcsi_callbacks hcsi_callbacks_server =
static const struct hcsi_callbacks hcsi_callbacks_server_27 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id,
.on_settings_frame = on_settings_frame,
.on_setting = on_setting,
.on_goaway = on_goaway_server_27,
.on_unexpected_frame = on_unexpected_frame,
};
static const struct hcsi_callbacks hcsi_callbacks_client_27 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id_client,
.on_settings_frame = on_settings_frame,
.on_setting = on_setting,
.on_goaway = on_goaway_client_28 /* sic */,
.on_unexpected_frame = on_unexpected_frame,
};
static const struct hcsi_callbacks hcsi_callbacks_server_28 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id,
.on_settings_frame = on_settings_frame,
.on_setting = on_setting,
.on_goaway = on_goaway_server /* sic */,
.on_unexpected_frame = on_unexpected_frame,
};
static const struct hcsi_callbacks hcsi_callbacks_client_28 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id_client,
.on_settings_frame = on_settings_frame,
.on_setting = on_setting,
.on_goaway = on_goaway_client_28,
.on_unexpected_frame = on_unexpected_frame,
};
static const struct hcsi_callbacks hcsi_callbacks_server_29 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id,
@ -7539,13 +7653,13 @@ static const struct hcsi_callbacks hcsi_callbacks_server =
.on_unexpected_frame = on_unexpected_frame,
};
static const struct hcsi_callbacks hcsi_callbacks =
static const struct hcsi_callbacks hcsi_callbacks_client_29 =
{
.on_cancel_push = on_cancel_push,
.on_max_push_id = on_max_push_id_client,
.on_settings_frame = on_settings_frame,
.on_setting = on_setting,
.on_goaway = on_goaway,
.on_goaway = on_goaway_client,
.on_unexpected_frame = on_unexpected_frame,
};
@ -7554,10 +7668,36 @@ static lsquic_stream_ctx_t *
hcsi_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
{
struct ietf_full_conn *const conn = (void *) stream_if_ctx;
const struct hcsi_callbacks *callbacks;
conn->ifc_stream_hcsi = stream;
switch ((!!(conn->ifc_flags & IFC_SERVER) << 8) | conn->ifc_conn.cn_version)
{
case (0 << 8) | LSQVER_ID27:
callbacks = &hcsi_callbacks_client_27;
break;
case (1 << 8) | LSQVER_ID27:
callbacks = &hcsi_callbacks_server_27;
break;
case (0 << 8) | LSQVER_ID28:
callbacks = &hcsi_callbacks_client_28;
break;
case (1 << 8) | LSQVER_ID28:
callbacks = &hcsi_callbacks_server_28;
break;
case (0 << 8) | LSQVER_ID29:
callbacks = &hcsi_callbacks_client_29;
break;
default:
assert(0);
/* fallthru */
case (1 << 8) | LSQVER_ID29:
callbacks = &hcsi_callbacks_server_29;
break;
}
lsquic_hcsi_reader_init(&conn->ifc_hcsi.reader, &conn->ifc_conn,
conn->ifc_flags & IFC_SERVER ? &hcsi_callbacks_server : &hcsi_callbacks,
conn);
callbacks, conn);
lsquic_stream_wantread(stream, 1);
return stream_if_ctx;
}

View file

@ -5,7 +5,11 @@
/* [draft-ietf-quic-tls-23] Section 5.2 */
#define HSK_SALT_BUF "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7" \
"\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02"
#define HSK_SALT ((unsigned char *) HSK_SALT_BUF)
#define HSK_SALT_PRE29 ((unsigned char *) HSK_SALT_BUF)
/* [draft-ietf-quic-tls-29] Section 5.2 */
#define HSK_SALT ((unsigned char *) \
"\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97" \
"\x86\xf1\x9c\x61\x11\xe0\x43\x90\xa8\x99")
#define HSK_SALT_SZ (sizeof(HSK_SALT_BUF) - 1)
#define CLIENT_LABEL "client in"

View file

@ -9,7 +9,7 @@ enum trans_error_code
{
TEC_NO_ERROR = 0x0,
TEC_INTERNAL_ERROR = 0x1,
TEC_SERVER_BUSY = 0x2,
TEC_CONNECTION_REFUSED = 0x2,
TEC_FLOW_CONTROL_ERROR = 0x3,
TEC_STREAM_LIMIT_ERROR = 0x4,
TEC_STREAM_STATE_ERROR = 0x5,
@ -27,11 +27,12 @@ enum trans_error_code
#define MAX_IETF_CONN_DCIDS 8
/* [draft-ietf-quic-tls-25] Section 5.8 */
#define IETF_RETRY_KEY_BUF ((unsigned char *) \
"\x4d\x32\xec\xdb\x2a\x21\x33\xc8\x41\xe4\x04\x3d\xf2\x7d\x44\x30")
#define IETF_RETRY_KEY_SZ 16
#define IETF_RETRY_NONCE_BUF ((unsigned char *) \
"\x4d\x16\x11\xd0\x55\x13\xa5\x52\xc5\x87\xd5\x75")
#define IETF_RETRY_NONCE_SZ 12
#define N_IETF_RETRY_VERSIONS 2
extern const unsigned char *const lsquic_retry_key_buf[N_IETF_RETRY_VERSIONS];
extern const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS];
#define lsquic_version_2_retryver(ver_) ((ver_) > LSQVER_ID28)
#endif

View file

@ -1623,7 +1623,7 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
else if (conn->imc_flags & IMC_BAD_TRANS_PARAMS)
{
is_app = 0;
error_code = TEC_PROTOCOL_VIOLATION;
error_code = TEC_TRANSPORT_PARAMETER_ERROR;
reason = "bad transport parameters";
rlen = 24;
}

View file

@ -220,6 +220,34 @@ lsquic_cid_from_packet (const unsigned char *buf, size_t bufsz,
/* See [draft-ietf-quic-transport-28], Section 12.4 (Table 3) */
const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
{
[LSQVER_ID29] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
| QUIC_FTBIT_TIMESTAMP
,
},
[LSQVER_ID28] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,

View file

@ -1369,7 +1369,7 @@ lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *ctl)
{
return (ctl->sc_flags & SC_PACE)
&& !lsquic_pacer_can_schedule(&ctl->sc_pacer,
ctl->sc_n_scheduled + ctl->sc_n_in_flight_all);
ctl->sc_n_in_flight_all);
}
@ -1674,6 +1674,45 @@ send_ctl_maybe_zero_pad (struct lsquic_send_ctl *ctl,
}
/* Predict whether lsquic_send_ctl_next_packet_to_send() will return a
* packet by mimicking its logic. Returns true if packet will be returned,
* false otherwise.
*/
int
lsquic_send_ctl_next_packet_to_send_predict (struct lsquic_send_ctl *ctl)
{
const struct lsquic_packet_out *packet_out;
unsigned n_rtos;
n_rtos = ~0u;
TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next)
{
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
&& 0 == ctl->sc_next_limit
&& 0 != (n_rtos == ~0u ? /* Initialize once */
(n_rtos = send_ctl_get_n_consec_rtos(ctl)) : n_rtos))
{
LSQ_DEBUG("send prediction: no, n_rtos: %u", n_rtos);
return 0;
}
if ((packet_out->po_flags & PO_REPACKNO)
&& packet_out->po_regen_sz == packet_out->po_data_sz)
{
LSQ_DEBUG("send prediction: packet %"PRIu64" would be dropped, "
"continue", packet_out->po_packno);
continue;
}
LSQ_DEBUG("send prediction: yes, packet %"PRIu64", flags %u, frames 0x%X",
packet_out->po_packno, (unsigned) packet_out->po_flags,
(unsigned) packet_out->po_frame_types);
return 1;
}
LSQ_DEBUG("send prediction: no, no matching scheduled packets");
return 0;
}
lsquic_packet_out_t *
lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl, size_t size)
{
@ -1685,6 +1724,9 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl, size_t size)
if (!packet_out)
return NULL;
/* Note: keep logic in this function and in
* lsquic_send_ctl_next_packet_to_send_predict() in synch.
*/
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
&& send_ctl_get_n_consec_rtos(ctl))
{

View file

@ -168,6 +168,9 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *, struct lsquic_packet_out *);
struct lsquic_packet_out *
lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *, size_t);
int
lsquic_send_ctl_next_packet_to_send_predict (struct lsquic_send_ctl *);
void
lsquic_send_ctl_expire_all (lsquic_send_ctl_t *ctl);
@ -387,4 +390,9 @@ lsquic_send_ctl_begin_optack_detection (struct lsquic_send_ctl *);
void
lsquic_send_ctl_path_validated (struct lsquic_send_ctl *);
/* Has immediately sendable packets */
#define lsquic_send_ctl_has_sendable(ctl_) \
(lsquic_send_ctl_n_scheduled(ctl_) > 0 \
&& lsquic_send_ctl_next_packet_to_send_predict(ctl_))
#endif

View file

@ -1747,6 +1747,14 @@ void
lsquic_stream_received_goaway (lsquic_stream_t *stream)
{
SM_HISTORY_APPEND(stream, SHE_GOAWAY_IN);
if (stream->stream_flags & STREAM_GOAWAY_IN)
{
LSQ_DEBUG("ignore duplicate GOAWAY");
return;
}
stream->stream_flags |= STREAM_GOAWAY_IN;
if (0 == stream->read_offset &&
stream->data_in->di_if->di_empty(stream->data_in))
fake_reset_unused_stream(stream); /* Normal condition */

View file

@ -208,7 +208,7 @@ enum stream_flags {
STREAM_ONNEW_DONE = 1 << 17, /* on_new_stream has been called */
STREAM_PUSHING = 1 << 18,
STREAM_NOPUSH = 1 << 19, /* Disallow further push promises */
STREAM_UNUSED20 = 1 << 20, /* Unused */
STREAM_GOAWAY_IN = 1 << 20, /* Incoming GOAWAY has been processed */
STREAM_UNUSED21 = 1 << 21, /* Unused */
STREAM_RST_ACKED = 1 << 22, /* Packet containing RST has been acked */
STREAM_BLOCKED_SENT = 1 << 23, /* Stays set once a STREAM_BLOCKED frame is sent */

View file

@ -20,6 +20,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
#endif
[LSQVER_ID27] = { 0xFF, 0, 0, 27, },
[LSQVER_ID28] = { 0xFF, 0, 0, 28, },
[LSQVER_ID29] = { 0xFF, 0, 0, 29, },
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
};
@ -58,6 +59,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
#endif
[LSQVER_ID27] = "FF00001B",
[LSQVER_ID28] = "FF00001C",
[LSQVER_ID29] = "FF00001D",
[LSQVER_VERNEG] = "FAFAFAFA",
};

View file

@ -33,7 +33,7 @@ main (void)
};
HKDF_extract(secret, &secret_len, md, dcid.idbuf, dcid.len,
HSK_SALT, HSK_SALT_SZ);
HSK_SALT_PRE29, HSK_SALT_SZ);
assert(sizeof(expected_secret) == secret_len);
assert(0 == memcmp(secret, expected_secret, sizeof(expected_secret)));