diff --git a/.cirrus.yml b/.cirrus.yml index a3be05893..b4e245fad 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -8,7 +8,7 @@ task: - cd boringssl # This is so that both GQUIC and IETF branches build. Just picking # a known good revision: - - git checkout b117a3a0b7bd11fe6ebd503ec6b45d6b910b41a1 + - git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 - cmake . - make - cd - diff --git a/.travis.yml b/.travis.yml index 0ca735d1c..0c31521a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ before_script: - cd boringssl # This is so that both GQUIC and IETF branches build. Just picking # a known good revision: - - git checkout b117a3a0b7bd11fe6ebd503ec6b45d6b910b41a1 + - git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 - cmake . - make - cd - diff --git a/CHANGELOG b/CHANGELOG index 769f22d35..12db49170 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +2021-02-10 + - 2.29.0 + - [FEATURE] QUIC and HTTP/3 Internet Draft 34 support and v1 support. + The latter is turned off by default. + - Drop support for ID-28 and ID-32. + - [BUGFIX] IETF QUIC mini conn receive history (trechist): allow + unlimited inserts by dropping smallest elements. + - [BUGFIX] gQUIC: set STTL to correct value, issue #226. + - [BUGFIX] Account for poison packet gap when MTU probe was too large. + 2021-02-03 - 2.28.0 - [API] lsquic_ssl_sess_to_resume_info() is the new way to get diff --git a/Dockerfile b/Dockerfile index c6446349b..e74de5cb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ COPY ./ /src/lsquic/ RUN git clone https://boringssl.googlesource.com/boringssl && \ cd boringssl && \ - git checkout b117a3a0b7bd11fe6ebd503ec6b45d6b910b41a1 && \ + git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 && \ cmake . && \ make diff --git a/README.md b/README.md index ea96691f8..761ecdf9c 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,9 @@ and HTTP/3 functionality for servers and clients. Most of the code in this distribution is used in our own products: LiteSpeed Web Server, LiteSpeed ADC, and OpenLiteSpeed. -Currently supported QUIC versions are Q043, Q046, Q050, ID-27, ID-28, ID-29, -and ID-32. Support for newer versions is added soon after they are released. +Currently supported QUIC versions are v1 (disabled by default until the +QUIC RFC is released); Internet-Draft versions 34, 29, and 27; +and the older "Google" QUIC versions Q043, Q046, an Q050. Documentation ------------- @@ -48,7 +49,7 @@ You may need to install pre-requisites like zlib and libevent. 2. Use specific BoringSSL version ``` -git checkout b117a3a0b7bd11fe6ebd503ec6b45d6b910b41a1 +git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 ``` 3. Compile the library diff --git a/appveyor.yml b/appveyor.yml index d150094cb..17e7d147c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,7 +30,7 @@ build_script: cd boringssl - git checkout b117a3a0b7bd11fe6ebd503ec6b45d6b910b41a1 + git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 cmake -DCMAKE_GENERATOR_PLATFORM=x64 --config Debug -DBUILD_SHARED_LIBS=OFF -DOPENSSL_NO_ASM=1 . diff --git a/docs/apiref.rst b/docs/apiref.rst index 02f30233e..8453086e3 100644 --- a/docs/apiref.rst +++ b/docs/apiref.rst @@ -50,17 +50,18 @@ developed by the IETF. Both types are included in a single enum: IETF QUIC version ID (Internet-Draft) 27; this version is deprecated. - .. member:: LSQVER_ID28 - - IETF QUIC version ID 28; this version is deprecated. - .. member:: LSQVER_ID29 IETF QUIC version ID 29 - .. member:: LSQVER_ID32 + .. member:: LSQVER_ID34 + + IETF QUIC version ID 34 + + .. member:: LSQVER_I001 - IETF QUIC version ID 32 + IETF QUIC version 1. (This version is disabled by default until + the QUIC RFC is released). .. member:: N_LSQVER diff --git a/docs/conf.py b/docs/conf.py index 806b82f80..d23fddf8d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,9 +24,9 @@ author = u'LiteSpeed Technologies' # The short X.Y version -version = u'2.28' +version = u'2.29' # The full version, including alpha/beta/rc tags -release = u'2.28.0' +release = u'2.29.0' # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index 7e484ab00..dbbbdfd70 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,9 +16,9 @@ Most of the code in this distribution has been used in our own products -- `LiteSpeed Web Server`_, `LiteSpeed Web ADC`_, and OpenLiteSpeed_ -- since 2017. -Currently supported QUIC versions are Q043, Q046, Q050, ID-27, ID-28, -ID-29, and ID-32. -Support for newer versions will be added soon after they are released. +Currently supported QUIC versions are v1 (disabled by default until the +QUIC RFC is released); Internet-Draft versions 34, 29, and 27; +and the older "Google" QUIC versions Q043, Q046, an Q050. LSQUIC is licensed under the `MIT License`_; see LICENSE in the source distribution for details. diff --git a/include/lsquic.h b/include/lsquic.h index 13897c56b..529d85e75 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -24,7 +24,7 @@ extern "C" { #endif #define LSQUIC_MAJOR_VERSION 2 -#define LSQUIC_MINOR_VERSION 28 +#define LSQUIC_MINOR_VERSION 29 #define LSQUIC_PATCH_VERSION 0 /** @@ -82,19 +82,20 @@ enum lsquic_version LSQVER_ID27, /** - * IETF QUIC Draft-28; this version is deprecated. + * IETF QUIC Draft-29 */ - LSQVER_ID28, + LSQVER_ID29, /** - * IETF QUIC Draft-29 + * IETF QUIC Draft-34 */ - LSQVER_ID29, + LSQVER_ID34, /** - * IETF QUIC Draft-32 + * IETF QUIC v1. Functionally the same as Draft-34, but marked + * experimental for now. */ - LSQVER_ID32, + LSQVER_I001, /** * Special version to trigger version negotiation. @@ -106,8 +107,8 @@ enum lsquic_version }; /** - * We currently support versions 43, 46, 50, Draft-27, Draft-28, Draft-29, - * and Draft-32. + * We currently support versions 43, 46, 50, Draft-27, Draft-29, Draft-34, + * and IETF QUIC v1. * @see lsquic_version */ #define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1) @@ -118,19 +119,21 @@ enum lsquic_version #define LSQUIC_FORCED_TCID0_VERSIONS ((1 << LSQVER_046)|(1 << LSQVER_050)) #define LSQUIC_EXPERIMENTAL_VERSIONS ( \ + (1 << LSQVER_I001) | \ (1 << LSQVER_VERNEG) | LSQUIC_EXPERIMENTAL_Q098) -#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28)) +#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_ID27)) #define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043) -#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \ +#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) \ | (1 << LSQVER_ID29) \ - | (1 << LSQVER_ID32) | (1 << LSQVER_VERNEG)) + | (1 << LSQVER_ID34) \ + | (1 << LSQVER_I001) | (1 << LSQVER_VERNEG)) -#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \ +#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) \ | (1 << LSQVER_ID29) \ - | (1 << LSQVER_ID32) | (1 << LSQVER_VERNEG)) + | (1 << LSQVER_ID34) | (1 << LSQVER_VERNEG)) enum lsquic_hsk_status { diff --git a/src/liblsquic/gen-verstrs.pl b/src/liblsquic/gen-verstrs.pl index b372a75d2..0aea69626 100755 --- a/src/liblsquic/gen-verstrs.pl +++ b/src/liblsquic/gen-verstrs.pl @@ -26,6 +26,12 @@ push @all_versions, $1; push @all_alpns, "h3-$2"; } + if (/^\s*(LSQVER_I(\d{3}))\b/) { + push @all_versions, $1; + if (not grep 'h3' eq $_, @all_alpns) { + push @all_alpns, "h3"; + } + } } } diff --git a/src/liblsquic/lsquic_enc_sess.h b/src/liblsquic/lsquic_enc_sess.h index ce9a626b6..a7d0bf216 100644 --- a/src/liblsquic/lsquic_enc_sess.h +++ b/src/liblsquic/lsquic_enc_sess.h @@ -339,9 +339,9 @@ 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_ID32 ? &lsquic_enc_session_common_ietf_v1 : \ + ver == LSQVER_ID34 ? &lsquic_enc_session_common_ietf_v1 : \ + ver == LSQVER_I001 ? &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 ) diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index ea6190be3..e6ea02a05 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -72,10 +72,10 @@ static const struct alpn_map { const unsigned char *alpn; } s_h3_alpns[] = { { LSQVER_ID27, (unsigned char *) "\x05h3-27", }, - { LSQVER_ID28, (unsigned char *) "\x05h3-28", }, { LSQVER_ID29, (unsigned char *) "\x05h3-29", }, - { LSQVER_ID32, (unsigned char *) "\x05h3-32", }, - { LSQVER_VERNEG, (unsigned char *) "\x05h3-32", }, + { LSQVER_ID34, (unsigned char *) "\x05h3-34", }, + { LSQVER_I001, (unsigned char *) "\x02h3", }, + { LSQVER_VERNEG, (unsigned char *) "\x05h3-34", }, }; struct enc_sess_iquic; @@ -926,6 +926,10 @@ iquic_esfi_create_client (const char *hostname, ERR_error_string(ERR_get_error(), errbuf)); goto err; } +#if BORINGSSL_API_VERSION >= 13 + SSL_set_quic_use_legacy_codepoint(enc_sess->esi_ssl, + enc_sess->esi_ver_neg->vn_ver < LSQVER_ID34); +#endif transpa_len = gen_trans_params(enc_sess, trans_params, sizeof(trans_params)); @@ -1109,6 +1113,7 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid) struct header_prot *hp; size_t hsk_secret_sz, key_len; unsigned cliser, i; + const unsigned char *salt; unsigned char hsk_secret[EVP_MAX_MD_SIZE]; unsigned char secret[2][SHA256_DIGEST_LENGTH]; /* client, server */ unsigned char key[2][EVP_MAX_KEY_LENGTH]; @@ -1131,12 +1136,17 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid) pair->ykp_thresh = IQUIC_INVALID_PACKNO; hp = &enc_sess->esi_hsk_hps[ENC_LEV_CLEAR]; + if (enc_sess->esi_conn->cn_version < LSQVER_ID29) + salt = HSK_SALT_PRE29; + else if (enc_sess->esi_conn->cn_version < LSQVER_ID34) + salt = HSK_SALT_PRE33; + else + salt = HSK_SALT; HKDF_extract(hsk_secret, &hsk_secret_sz, md, cid->idbuf, cid->len, - enc_sess->esi_conn->cn_version < LSQVER_ID29 - ? HSK_SALT_PRE29 : HSK_SALT, HSK_SALT_SZ); + salt, HSK_SALT_SZ); if (enc_sess->esi_flags & ESI_LOG_SECRETS) { - LSQ_DEBUG("handshake salt: %s", HEXSTR(HSK_SALT, HSK_SALT_SZ, hexbuf)); + LSQ_DEBUG("handshake salt: %s", HEXSTR(salt, HSK_SALT_SZ, hexbuf)); LSQ_DEBUG("handshake secret: %s", HEXSTR(hsk_secret, hsk_secret_sz, hexbuf)); } @@ -1382,6 +1392,10 @@ iquic_esfi_init_server (enc_session_t *enc_session_p) ERR_error_string(ERR_get_error(), u.errbuf)); return -1; } +#if BORINGSSL_API_VERSION >= 13 + SSL_set_quic_use_legacy_codepoint(enc_sess->esi_ssl, + enc_sess->esi_conn->cn_version < LSQVER_ID34); +#endif if (!(SSL_set_quic_method(enc_sess->esi_ssl, &cry_quic_method))) { LSQ_INFO("could not set stream method"); @@ -3327,6 +3341,9 @@ const unsigned char *const lsquic_retry_key_buf[N_IETF_RETRY_VERSIONS] = /* [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", + /* [draft-ietf-quic-tls-33] Section 5.8 */ + (unsigned char *) + "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e", }; @@ -3336,6 +3353,8 @@ const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS] = (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", + /* [draft-ietf-quic-tls-33] Section 5.8 */ + (unsigned char *) "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb", }; diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index 39dac7960..4d1801900 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -674,7 +674,7 @@ lsquic_engine_new (unsigned flags, { int sz = lsquic_enc_sess_ietf_gen_quic_ctx( &engine->pub.enp_settings, - i == 0 ? LSQVER_ID27 : LSQVER_ID28, + i == 0 ? LSQVER_ID27 : LSQVER_ID29, engine->pub.enp_quic_ctx_buf[i], sizeof(engine->pub.enp_quic_ctx_buf)); if (sz < 0) diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index af8b2a48d..3005ea22b 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -3314,7 +3314,7 @@ try_to_begin_migration (struct ietf_full_conn *conn, return BM_NOT_MIGRATING; } - if (conn->ifc_conn.cn_version <= LSQVER_ID28 /* Starting with ID-29, + if (conn->ifc_conn.cn_version <= LSQVER_ID27 /* 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. */ @@ -7566,16 +7566,16 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn, */ if (!verneg_ok(conn)) { - ABORT_ERROR("version negotiation not permitted in this version " - "of QUIC"); + ABORT_WITH_FLAG(conn, LSQ_LOG_NOTICE, IFC_ERROR, + "version negotiation not permitted in this version of QUIC"); return -1; } versions &= conn->ifc_u.cli.ifcli_ver_neg.vn_supp; if (0 == versions) { - ABORT_ERROR("client does not support any of the server-specified " - "versions"); + ABORT_WITH_FLAG(conn, LSQ_LOG_NOTICE, IFC_ERROR, + "client does not support any of the server-specified versions"); return -1; } @@ -7663,13 +7663,12 @@ ietf_full_conn_ci_packet_too_large (struct lsquic_conn *lconn, assert(packet_out->po_lflags & POL_HEADER_PROT); #endif - lsquic_senhist_add(&conn->ifc_send_ctl.sc_senhist, packet_out->po_packno); - lsquic_send_ctl_sanity_check(&conn->ifc_send_ctl); if (packet_out->po_flags & PO_MTU_PROBE) { LSQ_DEBUG("%zu-byte MTU probe in packet %"PRIu64" is too large", lsquic_packet_out_sent_sz(&conn->ifc_conn, packet_out), packet_out->po_packno); + lsquic_send_ctl_mtu_not_sent(&conn->ifc_send_ctl, packet_out); mtu_probe_too_large(conn, packet_out); } else @@ -9041,7 +9040,7 @@ on_goaway_server_27 (void *ctx, uint64_t stream_id) static void -on_goaway_client_28 (void *ctx, uint64_t stream_id) +on_goaway_client_27 (void *ctx, uint64_t stream_id) { struct ietf_full_conn *const conn = ctx; struct lsquic_stream *stream; @@ -9348,30 +9347,7 @@ static const struct hcsi_callbacks hcsi_callbacks_client_27 = .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, - .on_priority_update = on_priority_update_client, -}; - - -static const struct hcsi_callbacks hcsi_callbacks_server_28 = -{ - .on_cancel_push = on_cancel_push_server, - .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, - .on_priority_update = on_priority_update_server, -}; - -static const struct hcsi_callbacks hcsi_callbacks_client_28 = -{ - .on_cancel_push = on_cancel_push_client, - .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_goaway = on_goaway_client_27, .on_unexpected_frame = on_unexpected_frame, .on_priority_update = on_priority_update_client, }; @@ -9416,21 +9392,17 @@ hcsi_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 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: - case (0 << 8) | LSQVER_ID32: + case (0 << 8) | LSQVER_ID34: + case (0 << 8) | LSQVER_I001: callbacks = &hcsi_callbacks_client_29; break; default: assert(0); /* fallthru */ case (1 << 8) | LSQVER_ID29: - case (1 << 8) | LSQVER_ID32: + case (1 << 8) | LSQVER_ID34: + case (1 << 8) | LSQVER_I001: callbacks = &hcsi_callbacks_server_29; break; } diff --git a/src/liblsquic/lsquic_handshake.c b/src/liblsquic/lsquic_handshake.c index 6e6176215..114be4386 100644 --- a/src/liblsquic/lsquic_handshake.c +++ b/src/liblsquic/lsquic_handshake.c @@ -1963,13 +1963,12 @@ gen_rej1_data (struct lsquic_enc_session *enc_session, uint8_t *data, int len; EVP_PKEY * rsa_priv_key; SSL_CTX *ctx = enc_session->ssl_ctx; - const struct lsquic_engine_settings *const settings = - &enc_session->enpub->enp_settings; hs_ctx_t *const hs_ctx = &enc_session->hs_ctx; int scfg_len = enc_session->server_config->lsc_scfg->info.scfg_len; uint8_t *scfg_data = enc_session->server_config->lsc_scfg->scfg; size_t msg_len; struct message_writer mw; + uint64_t sttl; rsa_priv_key = SSL_CTX_get0_privatekey(ctx); if (!rsa_priv_key) @@ -2029,7 +2028,7 @@ gen_rej1_data (struct lsquic_enc_session *enc_session, uint8_t *data, MSG_LEN_ADD(msg_len, scfg_len); MSG_LEN_ADD(msg_len, STK_LENGTH); MSG_LEN_ADD(msg_len, SNO_LENGTH); - MSG_LEN_ADD(msg_len, sizeof(settings->es_sttl)); + MSG_LEN_ADD(msg_len, sizeof(sttl)); MSG_LEN_ADD(msg_len, lsquic_str_len(&hs_ctx->prof)); if (hs_ctx->ccert) MSG_LEN_ADD(msg_len, hs_ctx->ccert->len); @@ -2055,6 +2054,8 @@ gen_rej1_data (struct lsquic_enc_session *enc_session, uint8_t *data, lsquic_str_setlen(&enc_session->ssno, SNO_LENGTH); } RAND_bytes((uint8_t *) lsquic_str_buf(&enc_session->ssno), SNO_LENGTH); + sttl = enc_session->enpub->enp_server_config->lsc_scfg->info.expy + - (uint64_t) time(NULL); MW_BEGIN(&mw, QTAG_REJ, 7, data); MW_WRITE_LS_STR(&mw, QTAG_STK, &enc_session->sstk); @@ -2062,8 +2063,7 @@ gen_rej1_data (struct lsquic_enc_session *enc_session, uint8_t *data, MW_WRITE_LS_STR(&mw, QTAG_PROF, &hs_ctx->prof); MW_WRITE_BUFFER(&mw, QTAG_SCFG, scfg_data, scfg_len); MW_WRITE_BUFFER(&mw, QTAG_RREJ, &hs_ctx->rrej, sizeof(hs_ctx->rrej)); - MW_WRITE_BUFFER(&mw, QTAG_STTL, &settings->es_sttl, - sizeof(settings->es_sttl)); + MW_WRITE_BUFFER(&mw, QTAG_STTL, &sttl, sizeof(sttl)); if (hs_ctx->ccert) MW_WRITE_BUFFER(&mw, QTAG_CRT, hs_ctx->ccert->buf, hs_ctx->ccert->len); MW_END(&mw); diff --git a/src/liblsquic/lsquic_hkdf.h b/src/liblsquic/lsquic_hkdf.h index d32b7d181..93b344b0a 100644 --- a/src/liblsquic/lsquic_hkdf.h +++ b/src/liblsquic/lsquic_hkdf.h @@ -7,9 +7,13 @@ "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02" #define HSK_SALT_PRE29 ((unsigned char *) HSK_SALT_BUF) /* [draft-ietf-quic-tls-29] Section 5.2 */ -#define HSK_SALT ((unsigned char *) \ +#define HSK_SALT_PRE33 ((unsigned char *) \ "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97" \ "\x86\xf1\x9c\x61\x11\xe0\x43\x90\xa8\x99") +/* [draft-ietf-quic-tls-33] Section 5.2 */ +#define HSK_SALT ((unsigned char *) \ + "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17" \ + "\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a") #define HSK_SALT_SZ (sizeof(HSK_SALT_BUF) - 1) #define CLIENT_LABEL "client in" diff --git a/src/liblsquic/lsquic_hq.h b/src/liblsquic/lsquic_hq.h index 44984e343..d972e780d 100644 --- a/src/liblsquic/lsquic_hq.h +++ b/src/liblsquic/lsquic_hq.h @@ -78,6 +78,7 @@ enum http_error_code HEC_REQUEST_REJECTED = 0x10B, HEC_REQUEST_CANCELLED = 0x10C, HEC_REQUEST_INCOMPLETE = 0x10D, + HEC_MESSAGE_ERROR = 0x10E, HEC_CONNECT_ERROR = 0x10F, HEC_VERSION_FALLBACK = 0x110, HEC_QPACK_DECOMPRESSION_FAILED = 0x200, diff --git a/src/liblsquic/lsquic_ietf.h b/src/liblsquic/lsquic_ietf.h index e0bfc136c..73a04bb87 100644 --- a/src/liblsquic/lsquic_ietf.h +++ b/src/liblsquic/lsquic_ietf.h @@ -4,7 +4,7 @@ /* Things specific to the IETF version of QUIC that do not fit anywhere else */ -/* [draft-ietf-quic-transport-31] Section 20 */ +/* [draft-ietf-quic-transport-33] Section 20 */ enum trans_error_code { TEC_NO_ERROR = 0x0, @@ -23,6 +23,7 @@ enum trans_error_code TEC_CRYPTO_BUFFER_EXCEEDED = 0xD, TEC_KEY_UPDATE_ERROR = 0xE, TEC_AEAD_LIMIT_REACHED = 0xF, + TEC_NO_VIABLE_PATH = 0x10, }; /* Must be at least two */ @@ -32,9 +33,12 @@ enum trans_error_code #define IETF_RETRY_KEY_SZ 16 #define IETF_RETRY_NONCE_SZ 12 -#define N_IETF_RETRY_VERSIONS 2 +#define N_IETF_RETRY_VERSIONS 3 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) +#define lsquic_version_2_retryver(ver_) ( \ + (ver_) <= LSQVER_ID27 ? 0 : \ + (ver_) <= LSQVER_ID34 ? 1 : \ + 2) #endif diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index 933440adc..17641b391 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1378,15 +1378,10 @@ imico_switch_to_trechist (struct ietf_mini_conn *conn) if (conn->imc_recvd_packnos.bitmasks[pns]) { lsquic_imico_rechist_init(&iter, conn, pns); - if (0 != lsquic_trechist_copy_ranges(&masks[pns], + lsquic_trechist_copy_ranges(&masks[pns], elems + TRECHIST_MAX_RANGES * pns, &iter, lsquic_imico_rechist_first, - lsquic_imico_rechist_next)) - { - LSQ_WARN("cannot copy ranges from bitmask to trechist"); - free(elems); - return -1; - } + lsquic_imico_rechist_next); } else masks[pns] = 0; diff --git a/src/liblsquic/lsquic_parse_common.c b/src/liblsquic/lsquic_parse_common.c index c98cdea95..1c47e3a26 100644 --- a/src/liblsquic/lsquic_parse_common.c +++ b/src/liblsquic/lsquic_parse_common.c @@ -336,7 +336,7 @@ lsquic_dcid_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_ID32] = { + [LSQVER_I001] = { [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 @@ -346,7 +346,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | 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_PATH_CHALLENGE | QUIC_FTBIT_DATAGRAM | QUIC_FTBIT_RETIRE_CONNECTION_ID, [ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING @@ -366,7 +366,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | QUIC_FTBIT_DATAGRAM , }, - [LSQVER_ID29] = { + [LSQVER_ID34] = { [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 @@ -376,7 +376,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | 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_PATH_CHALLENGE | QUIC_FTBIT_DATAGRAM | QUIC_FTBIT_RETIRE_CONNECTION_ID, [ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING @@ -396,7 +396,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | QUIC_FTBIT_DATAGRAM , }, - [LSQVER_ID28] = { + [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 @@ -407,6 +407,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | QUIC_FTBIT_STREAMS_BLOCKED | QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING | QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE + | QUIC_FTBIT_DATAGRAM | QUIC_FTBIT_RETIRE_CONNECTION_ID, [ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING | QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE, @@ -422,6 +423,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] = | QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY | QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN | QUIC_FTBIT_TIMESTAMP + | QUIC_FTBIT_DATAGRAM , }, [LSQVER_ID27] = { diff --git a/src/liblsquic/lsquic_send_ctl.c b/src/liblsquic/lsquic_send_ctl.c index 245ad4181..4081b4505 100644 --- a/src/liblsquic/lsquic_send_ctl.c +++ b/src/liblsquic/lsquic_send_ctl.c @@ -641,6 +641,10 @@ send_ctl_add_poison (struct lsquic_send_ctl *ctl) { struct lsquic_packet_out *poison; + /* XXX Allocating the poison packet out of the regular pool can fail. + * This leads to a lot of error checking that could be skipped if we + * did not have to allocate this packet at all. + */ poison = lsquic_malo_get(ctl->sc_conn_pub->packet_out_malo); if (!poison) return -1; @@ -689,6 +693,33 @@ send_ctl_reschedule_poison (struct lsquic_send_ctl *ctl) } +static int +send_ctl_update_poison_hist (struct lsquic_send_ctl *ctl, + lsquic_packno_t packno) +{ + if (packno == ctl->sc_gap + 1) + { + assert(!(ctl->sc_flags & SC_POISON)); + lsquic_senhist_add(&ctl->sc_senhist, ctl->sc_gap); + if (0 != send_ctl_add_poison(ctl)) + return -1; + } + + return 0; +} + + +void +lsquic_send_ctl_mtu_not_sent (struct lsquic_send_ctl *ctl, + struct lsquic_packet_out *packet_out) +{ + (void) /* See comment in send_ctl_add_poison(): the plan is to make + this code path always succeed. */ + send_ctl_update_poison_hist(ctl, packet_out->po_packno); + lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno); +} + + int lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl, struct lsquic_packet_out *packet_out) @@ -699,13 +730,8 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl, assert(!(packet_out->po_flags & PO_ENCRYPTED)); ctl->sc_last_sent_time = packet_out->po_sent; pns = lsquic_packet_out_pns(packet_out); - if (packet_out->po_packno == ctl->sc_gap + 1) - { - assert(!(ctl->sc_flags & SC_POISON)); - lsquic_senhist_add(&ctl->sc_senhist, ctl->sc_gap); - if (0 != send_ctl_add_poison(ctl)) - return -1; - } + if (0 != send_ctl_update_poison_hist(ctl, packet_out->po_packno)) + return -1; LSQ_DEBUG("packet %"PRIu64" has been sent (frame types: %s)", packet_out->po_packno, lsquic_frame_types_to_str(frames, sizeof(frames), packet_out->po_frame_types)); diff --git a/src/liblsquic/lsquic_send_ctl.h b/src/liblsquic/lsquic_send_ctl.h index 18e4278d8..565fd11b6 100644 --- a/src/liblsquic/lsquic_send_ctl.h +++ b/src/liblsquic/lsquic_send_ctl.h @@ -155,6 +155,10 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *, struct lsquic_alarmset *, int lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *, struct lsquic_packet_out *); +void +lsquic_send_ctl_mtu_not_sent (struct lsquic_send_ctl *ctl, + struct lsquic_packet_out *); + int lsquic_send_ctl_got_ack (lsquic_send_ctl_t *, const struct ack_info *, lsquic_time_t, lsquic_time_t); diff --git a/src/liblsquic/lsquic_stream.c b/src/liblsquic/lsquic_stream.c index f062834df..f330d4622 100644 --- a/src/liblsquic/lsquic_stream.c +++ b/src/liblsquic/lsquic_stream.c @@ -1473,7 +1473,7 @@ verify_cl_on_fin (struct lsquic_stream *stream) if (stream->sm_data_in != 0 && stream->sm_cont_len != stream->sm_data_in) { lconn = stream->conn_pub->lconn; - lconn->cn_if->ci_abort_error(lconn, 1, HEC_GENERAL_PROTOCOL_ERROR, + lconn->cn_if->ci_abort_error(lconn, 1, HEC_MESSAGE_ERROR, "number of bytes in DATA frames of stream %"PRIu64" is %llu, " "while content-length specified of %llu", stream->id, stream->sm_data_in, stream->sm_cont_len); @@ -4811,7 +4811,7 @@ verify_cl_on_new_data_frame (struct lsquic_stream *stream, if (stream->sm_data_in > stream->sm_cont_len) { lconn = stream->conn_pub->lconn; - lconn->cn_if->ci_abort_error(lconn, 1, HEC_GENERAL_PROTOCOL_ERROR, + lconn->cn_if->ci_abort_error(lconn, 1, HEC_MESSAGE_ERROR, "number of bytes in DATA frames of stream %"PRIu64" exceeds " "content-length limit of %llu", stream->id, stream->sm_cont_len); } diff --git a/src/liblsquic/lsquic_trechist.c b/src/liblsquic/lsquic_trechist.c index e01d015de..c7cefe37c 100644 --- a/src/liblsquic/lsquic_trechist.c +++ b/src/liblsquic/lsquic_trechist.c @@ -29,12 +29,15 @@ find_free_slot (uint32_t slots) } -/* Returns 0 on success, 1 if dup, -1 if out of elements */ +/* When capacity is reached, smallest element is removed. When the number + * of elements in a single range cannot be represented by te_count, an + * error is returned. This is the only error this function returns. + */ int lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems, uint32_t packno) { - struct trechist_elem *el, *prev; + struct trechist_elem *el, *prev, *cur, *next; unsigned idx; if (*mask == 0) @@ -54,17 +57,22 @@ lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems, goto insert_before; if (packno == el->te_low - 1) { - if (el->te_count == UCHAR_MAX) - return -1; - --el->te_low; - ++el->te_count; - if (el->te_next && el->te_low == TE_HIGH(&elems[el->te_next]) + 1) + if (el->te_next && el->te_low == TE_HIGH(&elems[el->te_next]) + 2) { + if (el->te_count + elems[el->te_next].te_count - 1 > UCHAR_MAX) + return -1; *mask &= ~(1u << el->te_next); - el->te_count += elems[el->te_next].te_count; + el->te_count += elems[el->te_next].te_count + 1; el->te_low = elems[el->te_next].te_low; el->te_next = elems[el->te_next].te_next; } + else + { + if (el->te_count == UCHAR_MAX) + return -1; + --el->te_low; + ++el->te_count; + } return 0; } if (packno == TE_HIGH(el) + 1) @@ -75,15 +83,18 @@ lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems, return 0; } if (packno >= el->te_low && packno <= TE_HIGH(el)) - return 1; /* Dup */ + return 0; /* Dup */ if (!el->te_next) break; /* insert tail */ prev = el; el = &elems[el->te_next]; } - if (*mask == ((1u << TRECHIST_MAX_RANGES) - 1)) - return -1; + if (*mask == TRECHIST_MAX_RANGES_MASK) + /* No need to insert element smaller than the smallest element + * already in our list. The new element "overflows". + */ + return 0; idx = find_free_slot(*mask); elems[idx].te_low = packno; @@ -95,10 +106,17 @@ lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems, insert_before: - if (*mask == ((1u << TRECHIST_MAX_RANGES) - 1)) - return -1; + if (*mask != TRECHIST_MAX_RANGES_MASK) + idx = find_free_slot(*mask); + else + { /* Drop last element and reuse its slot */ + for (next = &elems[el->te_next], cur = el; next->te_next; + cur = next, next = &elems[cur->te_next]) + ; + idx = cur->te_next; + cur->te_next = 0; + } - idx = find_free_slot(*mask); *mask |= 1u << idx;; if (el == elems) { @@ -159,7 +177,8 @@ lsquic_trechist_next (void *iter_p) } -int +/* First TRECHIST_MAX_RANGES ranges are copied */ +void lsquic_trechist_copy_ranges (trechist_mask_t *mask, struct trechist_elem *elems, void *src_rechist, const struct lsquic_packno_range * (*first) (void *), @@ -182,19 +201,13 @@ lsquic_trechist_copy_ranges (trechist_mask_t *mask, el->te_next = i + 1; } - if (!range && el) - { + if (el) el->te_next = 0; + + if (i < 32) *mask = (1u << i) - 1; - return 0; - } - else if (!el) - { - *mask = 0; - return 0; /* Must have been an empty */ - } else - return -1; + *mask = UINT32_MAX; } diff --git a/src/liblsquic/lsquic_trechist.h b/src/liblsquic/lsquic_trechist.h index b17fc8411..5c3bcd3bf 100644 --- a/src/liblsquic/lsquic_trechist.h +++ b/src/liblsquic/lsquic_trechist.h @@ -19,6 +19,7 @@ struct lsquic_packno_range; * UCHAR_MAX, which is how many different values can fit into te_next. */ #define TRECHIST_MAX_RANGES 16 +#define TRECHIST_MAX_RANGES_MASK ((1u << TRECHIST_MAX_RANGES) - 1) struct trechist_elem { @@ -58,7 +59,7 @@ lsquic_trechist_first (void *iter); const struct lsquic_packno_range * lsquic_trechist_next (void *iter); -int +void lsquic_trechist_copy_ranges (trechist_mask_t *mask /* This gets overwritten */, struct trechist_elem *elems, void *src_rechist, const struct lsquic_packno_range * (*first) (void *), diff --git a/src/liblsquic/lsquic_version.c b/src/liblsquic/lsquic_version.c index 39faa09fc..067b97fd4 100644 --- a/src/liblsquic/lsquic_version.c +++ b/src/liblsquic/lsquic_version.c @@ -19,9 +19,9 @@ static const unsigned char version_tags[N_LSQVER][4] = [LSQVER_098] = { 'Q', '0', '9', '8', }, #endif [LSQVER_ID27] = { 0xFF, 0, 0, 27, }, - [LSQVER_ID28] = { 0xFF, 0, 0, 28, }, [LSQVER_ID29] = { 0xFF, 0, 0, 29, }, - [LSQVER_ID32] = { 0xFF, 0, 0, 32, }, + [LSQVER_ID34] = { 0xFF, 0, 0, 34, }, + [LSQVER_I001] = { 0, 0, 0, 1, }, [LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, }, }; @@ -59,9 +59,9 @@ const char *const lsquic_ver2str[N_LSQVER] = { [LSQVER_098] = "Q098", #endif [LSQVER_ID27] = "FF00001B", - [LSQVER_ID28] = "FF00001C", [LSQVER_ID29] = "FF00001D", - [LSQVER_ID32] = "FF000020", + [LSQVER_ID34] = "FF000022", + [LSQVER_I001] = "00000001", [LSQVER_VERNEG] = "FAFAFAFA", }; diff --git a/tests/test_h3_framing.c b/tests/test_h3_framing.c index bdfab343a..959d02ff2 100644 --- a/tests/test_h3_framing.c +++ b/tests/test_h3_framing.c @@ -1141,9 +1141,9 @@ fuzz_guided_pwritev_testing (const char *input) case 1: version = LSQVER_046; break; case 2: version = LSQVER_050; break; case 3: version = LSQVER_ID27; break; - case 4: version = LSQVER_ID28; break; + case 4: version = LSQVER_ID29; break; default: - case 5: version = LSQVER_ID29; break; + case 5: version = LSQVER_ID34; break; } sched_immed = !!(buf[8] & 0x08); diff --git a/tests/test_trechist.c b/tests/test_trechist.c index adcf0fa95..f0040c220 100644 --- a/tests/test_trechist.c +++ b/tests/test_trechist.c @@ -16,6 +16,32 @@ #include "lsquic_trechist.h" +struct str_range_iter +{ + char *str; + struct lsquic_packno_range range; +}; + + +static const struct lsquic_packno_range * +next_str_range (void *ctx) +{ + struct str_range_iter *const str_iter = ctx; + + if (str_iter->str && str_iter->str[0] == '[') + { + str_iter->range.high = strtoul(str_iter->str + 1, &str_iter->str, 10); + assert('-' == *str_iter->str); + str_iter->range.low = strtoul(str_iter->str + 1, &str_iter->str, 10); + assert(']' == *str_iter->str); + ++str_iter->str; + return &str_iter->range; + } + else + return NULL; +} + + static void test_clone (trechist_mask_t src_mask, struct trechist_elem *src_elems) { @@ -23,14 +49,12 @@ test_clone (trechist_mask_t src_mask, struct trechist_elem *src_elems) struct trechist_elem *hist_elems; const struct lsquic_packno_range *ranges[2]; struct trechist_iter iters[2]; - int s; hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES); lsquic_trechist_iter(&iters[0], src_mask, src_elems); - s = lsquic_trechist_copy_ranges(&hist_mask, hist_elems, &iters[0], + lsquic_trechist_copy_ranges(&hist_mask, hist_elems, &iters[0], lsquic_trechist_first, lsquic_trechist_next); - assert(s == 0); lsquic_trechist_iter(&iters[0], src_mask, src_elems); lsquic_trechist_iter(&iters[1], hist_mask, hist_elems); @@ -254,10 +278,6 @@ basic_test (void) s = lsquic_trechist_insert(&hist_mask, hist_elems, 1); assert(("inserting packet number one is successful", 0 == s)); - s = lsquic_trechist_insert(&hist_mask, hist_elems, 1); - assert(("inserting packet number one again results in duplicate error", - s == 1)); - lsquic_trechist_iter(&iter, hist_mask, hist_elems); range = lsquic_trechist_first(&iter); assert(("first range returned correctly", range)); @@ -338,18 +358,168 @@ test_limits (void) s = lsquic_trechist_insert(&hist_mask, hist_elems, i); assert(s == -1); /* Overflow */ - for (i = 0; i < TRECHIST_MAX_RANGES - 1; ++i) + /* Always successful inserting new entries: */ + for (i = 0; i < TRECHIST_MAX_RANGES * 2; ++i) { s = lsquic_trechist_insert(&hist_mask, hist_elems, 1000 + 2 * i); assert(s == 0); } - s = lsquic_trechist_insert(&hist_mask, hist_elems, 1000 + 2 * i); - assert(s == -1); /* Out of ranges */ + /* Always successful inserting new entries in descending order, too: */ + for (i = 0; i < TRECHIST_MAX_RANGES * 2; ++i) + { + s = lsquic_trechist_insert(&hist_mask, hist_elems, 10000 - 2 * i); + assert(s == 0); + } + + /* Test merge where count exceeds max: */ + hist_mask = 0; + lsquic_trechist_copy_ranges(&hist_mask, hist_elems, + & (struct str_range_iter) { .str = "[400-202][200-1]", }, + next_str_range, next_str_range); + s = lsquic_trechist_insert(&hist_mask, hist_elems, 201); + assert(s == -1); free(hist_elems); } + +static void +test_overflow (void) +{ + trechist_mask_t mask; + struct trechist_elem *elems; + int s; + char buf[0x1000]; + + struct str_range_iter str_iter = { .str = + "[395-390]" /* 1 */ + "[385-380]" + "[375-370]" + "[365-360]" + "[355-350]" /* 5 */ + "[345-340]" + "[335-330]" + "[325-320]" + "[315-310]" + "[305-300]" /* 10 */ + "[295-290]" + "[285-280]" + "[275-270]" + "[265-260]" + "[255-250]" /* 15 */ + "[245-240]" /* 16 */ + "[235-230]" /* Overflow vvvvvv */ + "[225-220]" + "[215-210]" + "[205-200]" + "[195-190]" + "[185-180]" }; + + elems = malloc(sizeof(elems[0]) * TRECHIST_MAX_RANGES); + lsquic_trechist_copy_ranges(&mask, elems, &str_iter, next_str_range, + next_str_range); + + rechist2str(mask, elems, buf, sizeof(buf)); + assert(0 == strcmp(buf, + "[395-390]" /* 1 */ + "[385-380]" + "[375-370]" + "[365-360]" + "[355-350]" /* 5 */ + "[345-340]" + "[335-330]" + "[325-320]" + "[315-310]" + "[305-300]" /* 10 */ + "[295-290]" + "[285-280]" + "[275-270]" + "[265-260]" + "[255-250]" /* 15 */ + "[245-240]" /* 16 */)); + + s = lsquic_trechist_insert(&mask, elems, 400); + assert(s == 0); + rechist2str(mask, elems, buf, sizeof(buf)); + assert(0 == strcmp(buf, + "[400-400]" + "[395-390]" + "[385-380]" + "[375-370]" + "[365-360]" + "[355-350]" + "[345-340]" + "[335-330]" + "[325-320]" + "[315-310]" + "[305-300]" + "[295-290]" + "[285-280]" + "[275-270]" + "[265-260]" + "[255-250]" + )); + + /* One more for a good measure */ + s = lsquic_trechist_insert(&mask, elems, 402); + assert(s == 0); + rechist2str(mask, elems, buf, sizeof(buf)); + assert(0 == strcmp(buf, + "[402-402]" + "[400-400]" + "[395-390]" + "[385-380]" + "[375-370]" + "[365-360]" + "[355-350]" + "[345-340]" + "[335-330]" + "[325-320]" + "[315-310]" + "[305-300]" + "[295-290]" + "[285-280]" + "[275-270]" + "[265-260]" + )); + + s = lsquic_trechist_insert(&mask, elems, 401); + assert(s == 0); + s = lsquic_trechist_insert(&mask, elems, 500); + assert(s == 0); + s = lsquic_trechist_insert(&mask, elems, 200); + assert(s == 0); + s = lsquic_trechist_insert(&mask, elems, 267); + assert(s == 0); + + /* One more for a good measure */ + s = lsquic_trechist_insert(&mask, elems, 402); + assert(s == 0); + rechist2str(mask, elems, buf, sizeof(buf)); + assert(0 == strcmp(buf, + "[500-500]" + "[402-400]" + "[395-390]" + "[385-380]" + "[375-370]" + "[365-360]" + "[355-350]" + "[345-340]" + "[335-330]" + "[325-320]" + "[315-310]" + "[305-300]" + "[295-290]" + "[285-280]" + "[275-270]" + "[267-267]" + )); + + free(elems); +} + + int main (void) { @@ -357,6 +527,7 @@ main (void) test4(); test5(); test_limits(); + test_overflow(); return 0; }