From feca77f50d51ed16d7713457b6fbed1fff19b895 Mon Sep 17 00:00:00 2001 From: Dmitri Tikhonov Date: Fri, 21 Feb 2020 14:26:25 -0500 Subject: [PATCH] Add experimental support for delayed ACKs extension --- CMakeLists.txt | 1 + docs/apiref.rst | 13 + include/lsquic.h | 13 + src/liblsquic/lsquic_enc_sess_ietf.c | 24 +- src/liblsquic/lsquic_engine.c | 1 + src/liblsquic/lsquic_full_conn.c | 4 +- src/liblsquic/lsquic_full_conn_id24.c | 12 +- src/liblsquic/lsquic_full_conn_ietf.c | 179 +++++++++++- src/liblsquic/lsquic_mini_conn.c | 4 +- src/liblsquic/lsquic_mini_conn_ietf.c | 9 +- src/liblsquic/lsquic_packet_common.h | 5 + src/liblsquic/lsquic_parse.h | 15 +- src/liblsquic/lsquic_parse_Q050.c | 7 +- src/liblsquic/lsquic_parse_common.c | 2 +- src/liblsquic/lsquic_parse_gquic_common.c | 8 +- src/liblsquic/lsquic_parse_ietf_v1.c | 339 +++++++++------------- src/liblsquic/lsquic_parse_iquic_common.c | 194 +------------ src/liblsquic/lsquic_send_ctl.h | 2 + src/liblsquic/lsquic_trans_params.c | 54 +++- src/liblsquic/lsquic_trans_params.h | 1 + test/test_common.c | 5 + 21 files changed, 465 insertions(+), 427 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21ee437..081360f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -258,6 +258,7 @@ IF(CMAKE_BUILD_TYPE STREQUAL "Debug") enable_testing() ENDIF() + FIND_PROGRAM(SPHINX NAMES sphinx-build) IF(SPHINX) ADD_CUSTOM_TARGET(docs diff --git a/docs/apiref.rst b/docs/apiref.rst index f8074e3..b90fa3f 100644 --- a/docs/apiref.rst +++ b/docs/apiref.rst @@ -676,6 +676,15 @@ settings structure: Default value is :macro:`LSQUIC_DF_SPIN` + .. member:: int es_delayed_acks + + Enable delayed ACKs extension. Allowed values are 0 and 1. + + **Warning**: this is an experimental feature. Using it will most likely + lead to degraded performance. + + Default value is :macro:`LSQUIC_DF_DELAYED_ACKS` + To initialize the settings structure to library defaults, use the following convenience function: @@ -846,6 +855,10 @@ out of date. Please check your :file:`lsquic.h` for actual values.* Use Cubic by default. +.. macro:: LSQUIC_DF_DELAYED_ACKS + + Delayed ACKs are off by default. + Receiving Packets ----------------- diff --git a/include/lsquic.h b/include/lsquic.h index 61bc355..d0503c4 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -327,6 +327,9 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)( /** Turn spin bit on by default */ #define LSQUIC_DF_SPIN 1 +/** Turn off delayed ACKs extension by default */ +#define LSQUIC_DF_DELAYED_ACKS 0 + /* 1: Cubic; 2: BBR */ #define LSQUIC_DF_CC_ALGO 1 @@ -711,6 +714,16 @@ struct lsquic_engine_settings { * Default value is @ref LSQUIC_DF_SPIN */ int es_spin; + + /** + * Enable delayed ACKs extension. Allowed values are 0 and 1. + * + * Warning: this is an experimental feature. Using it will most likely + * lead to degraded performance. + * + * Default value is @ref LSQUIC_DF_DELAYED_ACKS + */ + int es_delayed_acks; }; /* Initialize `settings' to default values */ diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index b9f5d4a..60f33dc 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -559,6 +559,11 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf, params.tp_loss_bits = settings->es_ql_bits - 1; params.tp_set |= 1 << TPI_LOSS_BITS; } + if (settings->es_delayed_acks) + { + params.tp_numerics[TPI_MIN_ACK_DELAY] = 10000; /* TODO: make into a constant? make configurable? */ + params.tp_set |= 1 << TPI_MIN_ACK_DELAY; + } len = lsquic_tp_encode(¶ms, enc_sess->esi_flags & ESI_SERVER, buf, bufsz); if (len >= 0) @@ -1445,7 +1450,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess) struct transport_params *const trans_params = &enc_sess->esi_peer_tp; const uint8_t *params_buf; size_t bufsz; - char params_str[0x200]; + char *params_str; SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, ¶ms_buf, &bufsz); if (!params_buf) @@ -1459,9 +1464,20 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess) !(enc_sess->esi_flags & ESI_SERVER), trans_params)) { - lsquic_hexdump(params_buf, bufsz, params_str, sizeof(params_str)); - LSQ_DEBUG("could not parse peer transport parameters (%zd bytes):\n%s", - bufsz, params_str); + if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG)) + { + params_str = lsquic_mm_get_4k(&enc_sess->esi_enpub->enp_mm); + if (params_str) + { + lsquic_hexdump(params_buf, bufsz, params_str, 0x1000); + LSQ_DEBUG("could not parse peer transport parameters " + "(%zd bytes):\n%s", bufsz, params_str); + lsquic_mm_put_4k(&enc_sess->esi_enpub->enp_mm, params_str); + } + else + LSQ_DEBUG("could not parse peer transport parameters " + "(%zd bytes)", bufsz); + } return -1; } diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index d445c55..67c90f7 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -334,6 +334,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings, settings->es_allow_migration = LSQUIC_DF_ALLOW_MIGRATION; settings->es_ql_bits = LSQUIC_DF_QL_BITS; settings->es_spin = LSQUIC_DF_SPIN; + settings->es_delayed_acks = LSQUIC_DF_DELAYED_ACKS; } diff --git a/src/liblsquic/lsquic_full_conn.c b/src/liblsquic/lsquic_full_conn.c index e656563..14e6a2f 100644 --- a/src/liblsquic/lsquic_full_conn.c +++ b/src/liblsquic/lsquic_full_conn.c @@ -2185,7 +2185,9 @@ static unsigned process_packet_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len) { - enum quic_frame_type type = conn->fc_conn.cn_pf->pf_parse_frame_type(p[0]); + enum quic_frame_type type; + + type = conn->fc_conn.cn_pf->pf_parse_frame_type(p, len); packet_in->pi_frame_types |= 1 << type; recent_packet_hist_frames(conn, 0, 1 << type); return process_frames[type](conn, packet_in, p, len); diff --git a/src/liblsquic/lsquic_full_conn_id24.c b/src/liblsquic/lsquic_full_conn_id24.c index 730f872..d6620fb 100644 --- a/src/liblsquic/lsquic_full_conn_id24.c +++ b/src/liblsquic/lsquic_full_conn_id24.c @@ -5182,8 +5182,12 @@ static unsigned process_packet_frame (struct id24_full_conn *conn, struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) { - enum enc_level enc_level = lsquic_packet_in_enc_level(packet_in); - enum quic_frame_type type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p[0]); + enum enc_level enc_level; + enum quic_frame_type type; + char str[8 * 2 + 1]; + + enc_level = lsquic_packet_in_enc_level(packet_in); + type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p, len); if (lsquic_legal_frames_by_level[enc_level] & (1 << type)) { LSQ_DEBUG("about to process %s frame", frame_type_2_str[type]); @@ -5192,8 +5196,8 @@ process_packet_frame (struct id24_full_conn *conn, } else { - LSQ_DEBUG("invalid frame %u (byte=0x%02X) at encryption level %s", - type, p[0], lsquic_enclev2str[enc_level]); + LSQ_DEBUG("invalid frame %u (bytes: %s) at encryption level %s", + type, HEXSTR(p, MIN(len, 8), str), lsquic_enclev2str[enc_level]); return 0; } } diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index dabc591..9df2c5a 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -132,6 +132,7 @@ enum ifull_conn_flags IFC_PROC_CRYPTO = 1 << 26, IFC_MIGRA = 1 << 27, IFC_SPIN = 1 << 28, /* Spin bits are enabled */ + IFC_DELAYED_ACKS = 1 << 29, /* Delayed ACKs are enabled */ }; @@ -161,6 +162,7 @@ enum send SEND_MAX_STREAMS_UNI = SEND_MAX_STREAMS + SD_UNI, SEND_STOP_SENDING, SEND_HANDSHAKE_DONE, + SEND_ACK_FREQUENCY, N_SEND }; @@ -185,6 +187,7 @@ enum send_flags SF_SEND_MAX_STREAMS_UNI = 1 << SEND_MAX_STREAMS_UNI, SF_SEND_STOP_SENDING = 1 << SEND_STOP_SENDING, SF_SEND_HANDSHAKE_DONE = 1 << SEND_HANDSHAKE_DONE, + SF_SEND_ACK_FREQUENCY = 1 << SEND_ACK_FREQUENCY, }; #define SF_SEND_PATH_CHAL_ALL \ @@ -283,6 +286,14 @@ struct conn_path }; +struct inc_ack_stats /* Incoming ACK stats */ +{ + unsigned n_acks; /* Number of ACKs between ticks */ + float avg_acked; /* Packets acked between ticks */ + float avg_n_acks; /* Average number of ACKs */ +}; + + struct ietf_full_conn { struct lsquic_conn ifc_conn; @@ -336,6 +347,7 @@ struct ietf_full_conn /* Number ackable packets received since last ACK was sent: */ unsigned ifc_n_slack_akbl[N_PNS]; unsigned ifc_n_slack_all; /* App PNS only */ + unsigned ifc_max_retx_since_last_ack; uint64_t ifc_ecn_counts_in[N_PNS][4]; uint64_t ifc_ecn_counts_out[N_PNS][4]; lsquic_stream_id_t ifc_max_req_id; @@ -368,6 +380,10 @@ struct ietf_full_conn unsigned char ifc_first_active_cid_seqno; unsigned char ifc_ping_unretx_thresh; unsigned ifc_last_retire_prior_to; + unsigned ifc_ack_freq_seqno; + unsigned ifc_last_pack_tol; + unsigned ifc_max_ack_freq_seqno; /* Incoming */ + unsigned ifc_max_peer_ack_usec; lsquic_time_t ifc_last_live_update; struct conn_path ifc_paths[N_PATHS]; union { @@ -394,6 +410,7 @@ struct ietf_full_conn lsquic_time_t ifc_idle_to; lsquic_time_t ifc_ping_period; uint64_t ifc_last_max_data_off_sent; + struct inc_ack_stats ifc_ias; struct ack_info ifc_ack; }; @@ -1073,6 +1090,7 @@ ietf_full_conn_init (struct ietf_full_conn *conn, #define valid_stream_id(v) ((v) <= VINT_MAX_VALUE) conn->ifc_max_req_id = VINT_MAX_VALUE + 1; conn->ifc_ping_unretx_thresh = 20; + conn->ifc_max_retx_since_last_ack = MAX_RETR_PACKETS_SINCE_LAST_ACK; maybe_enable_spin(conn); return 0; } @@ -2992,6 +3010,16 @@ handshake_ok (struct lsquic_conn *lconn) conn->ifc_ping_period = 0; LSQ_DEBUG("PING period is set to %"PRIu64" usec", conn->ifc_ping_period); + if (conn->ifc_conn.cn_version > LSQVER_ID24 + && conn->ifc_settings->es_delayed_acks + && (params->tp_set & (1 << TPI_MIN_ACK_DELAY))) + { + LSQ_DEBUG("delayed ACKs enabled"); + conn->ifc_flags |= IFC_DELAYED_ACKS; + } + + conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000; + /* TODO: packet size */ dce = get_new_dce(conn); @@ -3844,6 +3872,40 @@ generate_handshake_done_frame (struct ietf_full_conn *conn, } +static void +generate_ack_frequency_frame (struct ietf_full_conn *conn, lsquic_time_t unused) +{ + struct lsquic_packet_out *packet_out; + unsigned need; + int sz; + + need = conn->ifc_conn.cn_pf->pf_ack_frequency_frame_size( + conn->ifc_ack_freq_seqno, 2, ACK_TIMEOUT); + packet_out = get_writeable_packet(conn, need); + if (!packet_out) + { + LSQ_DEBUG("cannot get writeable packet for ACK_FREQUENCY frame"); + return; + } + + conn->ifc_last_pack_tol = conn->ifc_ias.avg_acked; + sz = conn->ifc_conn.cn_pf->pf_gen_ack_frequency_frame( + packet_out->po_data + packet_out->po_data_sz, + lsquic_packet_out_avail(packet_out), + conn->ifc_ack_freq_seqno, conn->ifc_last_pack_tol, + conn->ifc_max_peer_ack_usec); + if (sz < 0) + { + ABORT_ERROR("gen_rst_frame failed"); + return; + } + lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, sz); + packet_out->po_frame_types |= QUIC_FTBIT_ACK_FREQUENCY; + ++conn->ifc_ack_freq_seqno; + conn->ifc_send_flags &= ~SF_SEND_ACK_FREQUENCY; +} + + static void generate_path_chal_frame (struct ietf_full_conn *conn, lsquic_time_t now, unsigned path_id) @@ -4073,16 +4135,55 @@ handshake_confirmed (struct ietf_full_conn *conn) } +static void +update_ema (float *val, unsigned new) +{ + if (*val) + *val = (new - *val) * 0.4 + *val; + else + *val = new; +} + + +static void +update_target_packet_tolerance (struct ietf_full_conn *conn, + const unsigned n_newly_acked) +{ + update_ema(&conn->ifc_ias.avg_n_acks, conn->ifc_ias.n_acks); + update_ema(&conn->ifc_ias.avg_acked, n_newly_acked); + LSQ_DEBUG("packtol logic: %u ACK frames (avg: %.2f), %u newly acked " + "(avg: %.1f), last sent %u", conn->ifc_ias.n_acks, + conn->ifc_ias.avg_n_acks, n_newly_acked, conn->ifc_ias.avg_acked, + conn->ifc_last_pack_tol); + if (conn->ifc_ias.avg_n_acks > 1.5 && conn->ifc_ias.avg_acked > 2.0 + && conn->ifc_ias.avg_acked > (float) conn->ifc_last_pack_tol) + { + LSQ_DEBUG("old packet tolerance target: %u, schedule ACK_FREQUENCY " + "increase", conn->ifc_last_pack_tol); + conn->ifc_send_flags |= SF_SEND_ACK_FREQUENCY; + } + else if (conn->ifc_ias.avg_n_acks < 1.5 + && conn->ifc_ias.avg_acked < (float) conn->ifc_last_pack_tol * 3 / 4) + { + LSQ_DEBUG("old packet tolerance target: %u, schedule ACK_FREQUENCY " + "decrease", conn->ifc_last_pack_tol); + conn->ifc_send_flags |= SF_SEND_ACK_FREQUENCY; + } +} + + static int process_ack (struct ietf_full_conn *conn, struct ack_info *acki, lsquic_time_t received, lsquic_time_t now) { enum packnum_space pns; lsquic_packno_t packno; + unsigned n_unacked; int one_rtt_acked; LSQ_DEBUG("Processing ACK"); one_rtt_acked = lsquic_send_ctl_1rtt_acked(&conn->ifc_send_ctl); + n_unacked = lsquic_send_ctl_n_unacked(&conn->ifc_send_ctl); if (0 == lsquic_send_ctl_got_ack(&conn->ifc_send_ctl, acki, received, now)) { pns = acki->pns; @@ -4097,6 +4198,9 @@ process_ack (struct ietf_full_conn *conn, struct ack_info *acki, ignore_init(conn); handshake_confirmed(conn); } + if (PNS_APP == pns && (conn->ifc_flags & IFC_DELAYED_ACKS)) + update_target_packet_tolerance(conn, + n_unacked - lsquic_send_ctl_n_unacked(&conn->ifc_send_ctl)); return 0; } else @@ -4851,13 +4955,17 @@ process_ack_frame (struct ietf_full_conn *conn, LSQ_DEBUG("Saved ACK"); conn->ifc_flags |= IFC_HAVE_SAVED_ACK; conn->ifc_saved_ack_received = packet_in->pi_received; + conn->ifc_ias.n_acks = 1; } else if (pns == PNS_APP) { if (0 == lsquic_merge_acks(&conn->ifc_ack, new_acki)) + { + ++conn->ifc_ias.n_acks; LSQ_DEBUG("merged into saved ACK, getting %s", (lsquic_acki2str(&conn->ifc_ack, conn->ifc_pub.mm->ack_str, MAX_ACKI_STR_SZ), conn->ifc_pub.mm->ack_str)); + } else { LSQ_DEBUG("could not merge new ACK into saved ACK"); @@ -5294,8 +5402,6 @@ process_new_token_frame (struct ietf_full_conn *conn, char *token_str; int parsed_len; - /* TODO: make receipt of NEW_TOKEN frame an error on the server */ - parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_token_frame(p, len, &token, &token_sz); if (parsed_len < 0) @@ -5454,6 +5560,58 @@ process_handshake_done_frame (struct ietf_full_conn *conn, } +static unsigned +process_ack_frequency_frame (struct ietf_full_conn *conn, + struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) +{ + uint64_t seqno, pack_tol, upd_mad; + int parsed_len; + + if (!(conn->ifc_flags & IFC_DELAYED_ACKS)) + { + ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION, + "Received unexpected ACK_FREQUENCY frame (not negotiated)"); + return 0; + } + + parsed_len = conn->ifc_conn.cn_pf->pf_parse_ack_frequency_frame(p, len, + &seqno, &pack_tol, &upd_mad); + if (parsed_len < 0) + return 0; + + EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "ACK_FREQUENCY(seqno: %"PRIu64"; " + "pack_tol: %"PRIu64"; upd: %"PRIu64") frame in", seqno, pack_tol, + upd_mad); + LSQ_DEBUG("ACK_FREQUENCY(seqno: %"PRIu64"; pack_tol: %"PRIu64"; " + "upd: %"PRIu64") frame in", seqno, pack_tol, upd_mad); + + if (pack_tol == 0) + { + ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION, + "Packet Tolerance of zero is invalid"); + return 0; + } + + if (conn->ifc_max_ack_freq_seqno > 0 + && seqno <= conn->ifc_max_ack_freq_seqno) + { + LSQ_DEBUG("ignore old ACK_FREQUENCY frame"); + return parsed_len; + } + conn->ifc_max_ack_freq_seqno = seqno; + + if (pack_tol < UINT_MAX) + { + LSQ_DEBUG("set packet tolerance to %"PRIu64, pack_tol); + conn->ifc_max_retx_since_last_ack = pack_tol; + } + + /* TODO: do something with max ack delay update */ + + return parsed_len; +} + + typedef unsigned (*process_frame_f)( struct ietf_full_conn *, struct lsquic_packet_in *, const unsigned char *p, size_t); @@ -5481,6 +5639,7 @@ static process_frame_f const process_frames[N_QUIC_FRAMES] = [QUIC_FRAME_STREAM] = process_stream_frame, [QUIC_FRAME_CRYPTO] = process_crypto_frame, [QUIC_FRAME_HANDSHAKE_DONE] = process_handshake_done_frame, + [QUIC_FRAME_ACK_FREQUENCY] = process_ack_frequency_frame, }; @@ -5488,8 +5647,12 @@ static unsigned process_packet_frame (struct ietf_full_conn *conn, struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) { - enum enc_level enc_level = lsquic_packet_in_enc_level(packet_in); - enum quic_frame_type type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p[0]); + enum enc_level enc_level; + enum quic_frame_type type; + char str[8 * 2 + 1]; + + enc_level = lsquic_packet_in_enc_level(packet_in); + type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p, len); if (lsquic_legal_frames_by_level[enc_level] & (1 << type)) { LSQ_DEBUG("about to process %s frame", frame_type_2_str[type]); @@ -5498,8 +5661,8 @@ process_packet_frame (struct ietf_full_conn *conn, } else { - LSQ_DEBUG("invalid frame %u (byte=0x%02X) at encryption level %s", - type, p[0], lsquic_enclev2str[enc_level]); + LSQ_DEBUG("invalid frame %u (bytes: %s) at encryption level %s", + type, HEXSTR(p, MIN(len, 8), str), lsquic_enclev2str[enc_level]); return 0; } } @@ -5684,7 +5847,7 @@ try_queueing_ack_app (struct ietf_full_conn *conn, { lsquic_time_t srtt, ack_timeout; - if (conn->ifc_n_slack_akbl[PNS_APP] >= MAX_RETR_PACKETS_SINCE_LAST_ACK + if (conn->ifc_n_slack_akbl[PNS_APP] >= conn->ifc_max_retx_since_last_ack || ((conn->ifc_flags & IFC_ACK_HAD_MISS) && was_missing && conn->ifc_n_slack_akbl[PNS_APP] > 0) || many_in_and_will_write(conn)) @@ -6363,6 +6526,7 @@ static void (*const send_funcs[N_SEND])( [SEND_PATH_RESP_PATH_1] = generate_path_resp_1, [SEND_PING] = generate_ping_frame, [SEND_HANDSHAKE_DONE] = generate_handshake_done_frame, + [SEND_ACK_FREQUENCY] = generate_ack_frequency_frame, }; @@ -6373,6 +6537,7 @@ static void (*const send_funcs[N_SEND])( |SF_SEND_PATH_CHAL_PATH_0|SF_SEND_PATH_CHAL_PATH_1\ |SF_SEND_PATH_RESP_PATH_0|SF_SEND_PATH_RESP_PATH_1\ |SF_SEND_PING|SF_SEND_HANDSHAKE_DONE\ + |SF_SEND_ACK_FREQUENCY\ |SF_SEND_STOP_SENDING) static enum tick_st diff --git a/src/liblsquic/lsquic_mini_conn.c b/src/liblsquic/lsquic_mini_conn.c index c66b67e..ea03751 100644 --- a/src/liblsquic/lsquic_mini_conn.c +++ b/src/liblsquic/lsquic_mini_conn.c @@ -656,7 +656,7 @@ static unsigned process_packet_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len) { - enum quic_frame_type type = mc->mc_conn.cn_pf->pf_parse_frame_type(p[0]); + enum quic_frame_type type = mc->mc_conn.cn_pf->pf_parse_frame_type(p, len); packet_in->pi_frame_types |= 1 << type; return process_frames[type](mc, packet_in, p, len); } @@ -761,7 +761,7 @@ process_regular_packet (struct mini_conn *mc, lsquic_packet_in_t *packet_in) p += len; else { - if (mc->mc_conn.cn_pf->pf_parse_frame_type(p[0]) != + if (mc->mc_conn.cn_pf->pf_parse_frame_type(p, pend - p) != QUIC_FRAME_CONNECTION_CLOSE) LSQ_WARN("error parsing frame: packno %"PRIu64"; sz: %u; type: " "0x%X", packet_in->pi_packno, packet_in->pi_data_sz, p[0]); diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index ef5fa33..b899e9c 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1019,7 +1019,7 @@ static unsigned imico_process_invalid_frame (IMICO_PROC_FRAME_ARGS) { LSQ_DEBUG("invalid frame %u (%s)", p[0], - frame_type_2_str[ conn->imc_conn.cn_pf->pf_parse_frame_type(p[0]) ]); + frame_type_2_str[ conn->imc_conn.cn_pf->pf_parse_frame_type(p, len) ]); return 0; } @@ -1056,8 +1056,11 @@ static unsigned imico_process_packet_frame (struct ietf_mini_conn *conn, struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) { - enum enc_level enc_level = lsquic_packet_in_enc_level(packet_in); - enum quic_frame_type type = conn->imc_conn.cn_pf->pf_parse_frame_type(p[0]); + enum enc_level enc_level; + enum quic_frame_type type; + + enc_level = lsquic_packet_in_enc_level(packet_in); + type = conn->imc_conn.cn_pf->pf_parse_frame_type(p, len); if (lsquic_legal_frames_by_level[enc_level] & (1 << type)) { packet_in->pi_frame_types |= 1 << type; diff --git a/src/liblsquic/lsquic_packet_common.h b/src/liblsquic/lsquic_packet_common.h index 59c6d31..119aed1 100644 --- a/src/liblsquic/lsquic_packet_common.h +++ b/src/liblsquic/lsquic_packet_common.h @@ -34,6 +34,7 @@ enum quic_frame_type QUIC_FRAME_RETIRE_CONNECTION_ID,/* I */ QUIC_FRAME_NEW_TOKEN, /* I */ QUIC_FRAME_HANDSHAKE_DONE, /* I */ + QUIC_FRAME_ACK_FREQUENCY, /* I */ N_QUIC_FRAMES }; @@ -62,6 +63,7 @@ enum quic_ft_bit { QUIC_FTBIT_NEW_TOKEN = 1 << QUIC_FRAME_NEW_TOKEN, QUIC_FTBIT_RETIRE_CONNECTION_ID = 1 << QUIC_FRAME_RETIRE_CONNECTION_ID, QUIC_FTBIT_HANDSHAKE_DONE = 1 << QUIC_FRAME_HANDSHAKE_DONE, + QUIC_FTBIT_ACK_FREQUENCY = 1 << QUIC_FRAME_ACK_FREQUENCY, }; static const char * const frame_type_2_str[N_QUIC_FRAMES] = { @@ -89,6 +91,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = { [QUIC_FRAME_NEW_TOKEN] = "QUIC_FRAME_NEW_TOKEN", [QUIC_FRAME_RETIRE_CONNECTION_ID] = "QUIC_FRAME_RETIRE_CONNECTION_ID", [QUIC_FRAME_HANDSHAKE_DONE] = "QUIC_FRAME_HANDSHAKE_DONE", + [QUIC_FRAME_ACK_FREQUENCY] = "QUIC_FRAME_ACK_FREQUENCY", }; #define QUIC_FRAME_PRELEN (sizeof("QUIC_FRAME_")) @@ -124,6 +127,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = { + 1 + \ QUIC_FRAME_SLEN(QUIC_FRAME_NEW_TOKEN) + 1 + \ QUIC_FRAME_SLEN(QUIC_FRAME_HANDSHAKE_DONE) + 1 + \ + QUIC_FRAME_SLEN(QUIC_FRAME_ACK_FREQUENCY) + 1 + \ 0 @@ -212,6 +216,7 @@ extern const char *const lsquic_pns2str[]; | QUIC_FTBIT_RETIRE_CONNECTION_ID \ | QUIC_FTBIT_NEW_TOKEN \ | QUIC_FTBIT_HANDSHAKE_DONE \ + | QUIC_FTBIT_ACK_FREQUENCY \ | QUIC_FTBIT_CRYPTO ) /* [draft-ietf-quic-transport-24] Section 1.2 */ diff --git a/src/liblsquic/lsquic_parse.h b/src/liblsquic/lsquic_parse.h index d0cbca6..7b60ec0 100644 --- a/src/liblsquic/lsquic_parse.h +++ b/src/liblsquic/lsquic_parse.h @@ -76,7 +76,7 @@ struct parse_funcs (*pf_parse_packet_in_finish) (struct lsquic_packet_in *packet_in, struct packin_parse_state *); enum quic_frame_type - (*pf_parse_frame_type) (unsigned char); + (*pf_parse_frame_type) (const unsigned char *, size_t); /* Return used buffer length or a negative value if there was not enough * room to write the stream frame. In the latter case, the negative of * the negative return value is the number of bytes required. The @@ -301,6 +301,15 @@ struct parse_funcs (*pf_parse_handshake_done_frame) (const unsigned char *buf, size_t buf_len); unsigned (*pf_handshake_done_frame_size) (void); + int + (*pf_gen_ack_frequency_frame) (unsigned char *buf, size_t buf_len, + uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad); + int + (*pf_parse_ack_frequency_frame) (const unsigned char *buf, size_t buf_len, + uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad); + unsigned + (*pf_ack_frequency_frame_size) (uint64_t seqno, uint64_t pack_tol, + uint64_t upd_mad); }; @@ -339,9 +348,9 @@ lsquic_Q050_parse_packet_in_long_begin (struct lsquic_packet_in *, size_t length int is_server, unsigned, struct packin_parse_state *); enum quic_frame_type -lsquic_parse_frame_type_gquic_Q035_thru_Q046 (unsigned char first_byte); +lsquic_parse_frame_type_gquic_Q035_thru_Q046 (const unsigned char *, size_t); -extern const enum quic_frame_type lsquic_iquic_byte2type[0x100]; +extern const enum quic_frame_type lsquic_iquic_byte2type[0x40]; size_t calc_stream_frame_header_sz_gquic (lsquic_stream_id_t stream_id, diff --git a/src/liblsquic/lsquic_parse_Q050.c b/src/liblsquic/lsquic_parse_Q050.c index 01abb45..6b6c133 100644 --- a/src/liblsquic/lsquic_parse_Q050.c +++ b/src/liblsquic/lsquic_parse_Q050.c @@ -785,9 +785,12 @@ static const enum quic_frame_type byte2frame_type_Q050[0x100] = static enum quic_frame_type -gquic_Q050_parse_frame_type (unsigned char b) +gquic_Q050_parse_frame_type (const unsigned char *buf, size_t len) { - return byte2frame_type_Q050[b]; + if (len > 0) + return byte2frame_type_Q050[buf[0]]; + else + return QUIC_FRAME_INVALID; } diff --git a/src/liblsquic/lsquic_parse_common.c b/src/liblsquic/lsquic_parse_common.c index ea39ec3..ffc7b7a 100644 --- a/src/liblsquic/lsquic_parse_common.c +++ b/src/liblsquic/lsquic_parse_common.c @@ -242,6 +242,6 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[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_HANDSHAKE_DONE + | QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY | QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN, }; diff --git a/src/liblsquic/lsquic_parse_gquic_common.c b/src/liblsquic/lsquic_parse_gquic_common.c index 72ff4fd..9974712 100644 --- a/src/liblsquic/lsquic_parse_gquic_common.c +++ b/src/liblsquic/lsquic_parse_gquic_common.c @@ -458,9 +458,13 @@ static const enum quic_frame_type byte2frame_type_Q035_thru_Q046[0x100] = enum quic_frame_type -lsquic_parse_frame_type_gquic_Q035_thru_Q046 (unsigned char b) +lsquic_parse_frame_type_gquic_Q035_thru_Q046 (const unsigned char *buf, + size_t len) { - return byte2frame_type_Q035_thru_Q046[b]; + if (len > 0) + return byte2frame_type_Q035_thru_Q046[buf[0]]; + else + return QUIC_FRAME_INVALID; } diff --git a/src/liblsquic/lsquic_parse_ietf_v1.c b/src/liblsquic/lsquic_parse_ietf_v1.c index 1d67fc7..0f30e39 100644 --- a/src/liblsquic/lsquic_parse_ietf_v1.c +++ b/src/liblsquic/lsquic_parse_ietf_v1.c @@ -1097,17 +1097,31 @@ ietf_v1_calc_crypto_frame_header_sz (uint64_t offset, unsigned data_sz) static enum quic_frame_type -ietf_v1_parse_frame_type (unsigned char byte) +ietf_v1_parse_frame_type (const unsigned char *buf, size_t len) { - return lsquic_iquic_byte2type[byte]; + uint64_t val; + int s; + + if (len > 0 && buf[0] < 0x40) + return lsquic_iquic_byte2type[buf[0]]; + + s = vint_read(buf, buf + len, &val); + if (s > 0 && (unsigned) s == (1u << vint_val2bits(val))) + switch (val) + { + case 0xAF: return QUIC_FRAME_ACK_FREQUENCY; + default: break; + } + + return QUIC_FRAME_INVALID; } static enum quic_frame_type -ietf_id24_parse_frame_type (unsigned char byte) +ietf_id24_parse_frame_type (const unsigned char *buf, size_t len) { /* This one does not have QUIC_FRAME_HANDSHAKE_DONE */ - static const enum quic_frame_type byte2type[0x100] = + static const enum quic_frame_type byte2type[0x40] = { [0x00] = QUIC_FRAME_PADDING, [0x01] = QUIC_FRAME_PING, @@ -1173,200 +1187,12 @@ ietf_id24_parse_frame_type (unsigned char byte) [0x3D] = QUIC_FRAME_INVALID, [0x3E] = QUIC_FRAME_INVALID, [0x3F] = QUIC_FRAME_INVALID, - [0x40] = QUIC_FRAME_INVALID, - [0x41] = QUIC_FRAME_INVALID, - [0x42] = QUIC_FRAME_INVALID, - [0x43] = QUIC_FRAME_INVALID, - [0x44] = QUIC_FRAME_INVALID, - [0x45] = QUIC_FRAME_INVALID, - [0x46] = QUIC_FRAME_INVALID, - [0x47] = QUIC_FRAME_INVALID, - [0x48] = QUIC_FRAME_INVALID, - [0x49] = QUIC_FRAME_INVALID, - [0x4A] = QUIC_FRAME_INVALID, - [0x4B] = QUIC_FRAME_INVALID, - [0x4C] = QUIC_FRAME_INVALID, - [0x4D] = QUIC_FRAME_INVALID, - [0x4E] = QUIC_FRAME_INVALID, - [0x4F] = QUIC_FRAME_INVALID, - [0x50] = QUIC_FRAME_INVALID, - [0x51] = QUIC_FRAME_INVALID, - [0x52] = QUIC_FRAME_INVALID, - [0x53] = QUIC_FRAME_INVALID, - [0x54] = QUIC_FRAME_INVALID, - [0x55] = QUIC_FRAME_INVALID, - [0x56] = QUIC_FRAME_INVALID, - [0x57] = QUIC_FRAME_INVALID, - [0x58] = QUIC_FRAME_INVALID, - [0x59] = QUIC_FRAME_INVALID, - [0x5A] = QUIC_FRAME_INVALID, - [0x5B] = QUIC_FRAME_INVALID, - [0x5C] = QUIC_FRAME_INVALID, - [0x5D] = QUIC_FRAME_INVALID, - [0x5E] = QUIC_FRAME_INVALID, - [0x5F] = QUIC_FRAME_INVALID, - [0x60] = QUIC_FRAME_INVALID, - [0x61] = QUIC_FRAME_INVALID, - [0x62] = QUIC_FRAME_INVALID, - [0x63] = QUIC_FRAME_INVALID, - [0x64] = QUIC_FRAME_INVALID, - [0x65] = QUIC_FRAME_INVALID, - [0x66] = QUIC_FRAME_INVALID, - [0x67] = QUIC_FRAME_INVALID, - [0x68] = QUIC_FRAME_INVALID, - [0x69] = QUIC_FRAME_INVALID, - [0x6A] = QUIC_FRAME_INVALID, - [0x6B] = QUIC_FRAME_INVALID, - [0x6C] = QUIC_FRAME_INVALID, - [0x6D] = QUIC_FRAME_INVALID, - [0x6E] = QUIC_FRAME_INVALID, - [0x6F] = QUIC_FRAME_INVALID, - [0x70] = QUIC_FRAME_INVALID, - [0x71] = QUIC_FRAME_INVALID, - [0x72] = QUIC_FRAME_INVALID, - [0x73] = QUIC_FRAME_INVALID, - [0x74] = QUIC_FRAME_INVALID, - [0x75] = QUIC_FRAME_INVALID, - [0x76] = QUIC_FRAME_INVALID, - [0x77] = QUIC_FRAME_INVALID, - [0x78] = QUIC_FRAME_INVALID, - [0x79] = QUIC_FRAME_INVALID, - [0x7A] = QUIC_FRAME_INVALID, - [0x7B] = QUIC_FRAME_INVALID, - [0x7C] = QUIC_FRAME_INVALID, - [0x7D] = QUIC_FRAME_INVALID, - [0x7E] = QUIC_FRAME_INVALID, - [0x7F] = QUIC_FRAME_INVALID, - [0x80] = QUIC_FRAME_INVALID, - [0x81] = QUIC_FRAME_INVALID, - [0x82] = QUIC_FRAME_INVALID, - [0x83] = QUIC_FRAME_INVALID, - [0x84] = QUIC_FRAME_INVALID, - [0x85] = QUIC_FRAME_INVALID, - [0x86] = QUIC_FRAME_INVALID, - [0x87] = QUIC_FRAME_INVALID, - [0x88] = QUIC_FRAME_INVALID, - [0x89] = QUIC_FRAME_INVALID, - [0x8A] = QUIC_FRAME_INVALID, - [0x8B] = QUIC_FRAME_INVALID, - [0x8C] = QUIC_FRAME_INVALID, - [0x8D] = QUIC_FRAME_INVALID, - [0x8E] = QUIC_FRAME_INVALID, - [0x8F] = QUIC_FRAME_INVALID, - [0x90] = QUIC_FRAME_INVALID, - [0x91] = QUIC_FRAME_INVALID, - [0x92] = QUIC_FRAME_INVALID, - [0x93] = QUIC_FRAME_INVALID, - [0x94] = QUIC_FRAME_INVALID, - [0x95] = QUIC_FRAME_INVALID, - [0x96] = QUIC_FRAME_INVALID, - [0x97] = QUIC_FRAME_INVALID, - [0x98] = QUIC_FRAME_INVALID, - [0x99] = QUIC_FRAME_INVALID, - [0x9A] = QUIC_FRAME_INVALID, - [0x9B] = QUIC_FRAME_INVALID, - [0x9C] = QUIC_FRAME_INVALID, - [0x9D] = QUIC_FRAME_INVALID, - [0x9E] = QUIC_FRAME_INVALID, - [0x9F] = QUIC_FRAME_INVALID, - [0xA0] = QUIC_FRAME_INVALID, - [0xA1] = QUIC_FRAME_INVALID, - [0xA2] = QUIC_FRAME_INVALID, - [0xA3] = QUIC_FRAME_INVALID, - [0xA4] = QUIC_FRAME_INVALID, - [0xA5] = QUIC_FRAME_INVALID, - [0xA6] = QUIC_FRAME_INVALID, - [0xA7] = QUIC_FRAME_INVALID, - [0xA8] = QUIC_FRAME_INVALID, - [0xA9] = QUIC_FRAME_INVALID, - [0xAA] = QUIC_FRAME_INVALID, - [0xAB] = QUIC_FRAME_INVALID, - [0xAC] = QUIC_FRAME_INVALID, - [0xAD] = QUIC_FRAME_INVALID, - [0xAE] = QUIC_FRAME_INVALID, - [0xAF] = QUIC_FRAME_INVALID, - [0xB0] = QUIC_FRAME_INVALID, - [0xB1] = QUIC_FRAME_INVALID, - [0xB2] = QUIC_FRAME_INVALID, - [0xB3] = QUIC_FRAME_INVALID, - [0xB4] = QUIC_FRAME_INVALID, - [0xB5] = QUIC_FRAME_INVALID, - [0xB6] = QUIC_FRAME_INVALID, - [0xB7] = QUIC_FRAME_INVALID, - [0xB8] = QUIC_FRAME_INVALID, - [0xB9] = QUIC_FRAME_INVALID, - [0xBA] = QUIC_FRAME_INVALID, - [0xBB] = QUIC_FRAME_INVALID, - [0xBC] = QUIC_FRAME_INVALID, - [0xBD] = QUIC_FRAME_INVALID, - [0xBE] = QUIC_FRAME_INVALID, - [0xBF] = QUIC_FRAME_INVALID, - [0xC0] = QUIC_FRAME_INVALID, - [0xC1] = QUIC_FRAME_INVALID, - [0xC2] = QUIC_FRAME_INVALID, - [0xC3] = QUIC_FRAME_INVALID, - [0xC4] = QUIC_FRAME_INVALID, - [0xC5] = QUIC_FRAME_INVALID, - [0xC6] = QUIC_FRAME_INVALID, - [0xC7] = QUIC_FRAME_INVALID, - [0xC8] = QUIC_FRAME_INVALID, - [0xC9] = QUIC_FRAME_INVALID, - [0xCA] = QUIC_FRAME_INVALID, - [0xCB] = QUIC_FRAME_INVALID, - [0xCC] = QUIC_FRAME_INVALID, - [0xCD] = QUIC_FRAME_INVALID, - [0xCE] = QUIC_FRAME_INVALID, - [0xCF] = QUIC_FRAME_INVALID, - [0xD0] = QUIC_FRAME_INVALID, - [0xD1] = QUIC_FRAME_INVALID, - [0xD2] = QUIC_FRAME_INVALID, - [0xD3] = QUIC_FRAME_INVALID, - [0xD4] = QUIC_FRAME_INVALID, - [0xD5] = QUIC_FRAME_INVALID, - [0xD6] = QUIC_FRAME_INVALID, - [0xD7] = QUIC_FRAME_INVALID, - [0xD8] = QUIC_FRAME_INVALID, - [0xD9] = QUIC_FRAME_INVALID, - [0xDA] = QUIC_FRAME_INVALID, - [0xDB] = QUIC_FRAME_INVALID, - [0xDC] = QUIC_FRAME_INVALID, - [0xDD] = QUIC_FRAME_INVALID, - [0xDE] = QUIC_FRAME_INVALID, - [0xDF] = QUIC_FRAME_INVALID, - [0xE0] = QUIC_FRAME_INVALID, - [0xE1] = QUIC_FRAME_INVALID, - [0xE2] = QUIC_FRAME_INVALID, - [0xE3] = QUIC_FRAME_INVALID, - [0xE4] = QUIC_FRAME_INVALID, - [0xE5] = QUIC_FRAME_INVALID, - [0xE6] = QUIC_FRAME_INVALID, - [0xE7] = QUIC_FRAME_INVALID, - [0xE8] = QUIC_FRAME_INVALID, - [0xE9] = QUIC_FRAME_INVALID, - [0xEA] = QUIC_FRAME_INVALID, - [0xEB] = QUIC_FRAME_INVALID, - [0xEC] = QUIC_FRAME_INVALID, - [0xED] = QUIC_FRAME_INVALID, - [0xEE] = QUIC_FRAME_INVALID, - [0xEF] = QUIC_FRAME_INVALID, - [0xF0] = QUIC_FRAME_INVALID, - [0xF1] = QUIC_FRAME_INVALID, - [0xF2] = QUIC_FRAME_INVALID, - [0xF3] = QUIC_FRAME_INVALID, - [0xF4] = QUIC_FRAME_INVALID, - [0xF5] = QUIC_FRAME_INVALID, - [0xF6] = QUIC_FRAME_INVALID, - [0xF7] = QUIC_FRAME_INVALID, - [0xF8] = QUIC_FRAME_INVALID, - [0xF9] = QUIC_FRAME_INVALID, - [0xFA] = QUIC_FRAME_INVALID, - [0xFB] = QUIC_FRAME_INVALID, - [0xFC] = QUIC_FRAME_INVALID, - [0xFD] = QUIC_FRAME_INVALID, - [0xFE] = QUIC_FRAME_INVALID, - [0xFF] = QUIC_FRAME_INVALID, }; - return byte2type[byte]; + + if (len > 1 && buf[0] < 0x40) + return byte2type[buf[0]]; + else + return QUIC_FRAME_INVALID; } @@ -1669,6 +1495,76 @@ ietf_v1_parse_two_varints (const unsigned char *buf, size_t len, uint64_t *vals[ } +/* vals[0] is the frame type */ +static unsigned +ietf_v1_frame_with_varints_size (unsigned n, uint64_t vals[]) +{ + unsigned vbits, size; + + assert(n > 0); + vbits = vint_val2bits(vals[0]); + size = 1 << vbits; + while (--n) + { + vbits = vint_val2bits(vals[n]); + size += 1 << vbits; + } + + return size; +} + + +/* vals[0] is the frame type */ +static int +ietf_v1_gen_frame_with_varints (unsigned char *buf, size_t len, + unsigned count, uint64_t vals[]) +{ + unsigned vbits, n; + unsigned char *p; + + if (ietf_v1_frame_with_varints_size(count, vals) > len) + return -1; + + p = buf; + for (n = 0; n < count; ++n) + { + vbits = vint_val2bits(vals[n]); + vint_write(p, vals[n], vbits, 1 << vbits); + p += 1 << vbits; + } + + return p - buf; +} + + +/* Frame type is checked when frame type is parsed. The only use here is + * to calculate skip length. + */ +static int +ietf_v1_parse_frame_with_varints (const unsigned char *buf, size_t len, + const uint64_t frame_type, unsigned count, uint64_t *vals[]) +{ + const unsigned char *p = buf; + const unsigned char *const end = p + len; + unsigned vbits, n; + int s; + + vbits = vint_val2bits(frame_type); + p += 1 << vbits; + + for (n = 0; n < count; ++n) + { + s = vint_read(p, end, vals[n]); + if (s < 0) + return s; + p += s; + } + + return p - buf; +} + + + static int ietf_v1_parse_stream_blocked_frame (const unsigned char *buf, size_t len, lsquic_stream_id_t *stream_id, uint64_t *offset) @@ -2251,6 +2147,49 @@ ietf_v1_parse_handshake_done_frame (const unsigned char *buf, size_t buf_len) } +static int +ietf_v1_gen_ack_frequency_frame (unsigned char *buf, size_t buf_len, + uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad) +{ + return ietf_v1_gen_frame_with_varints(buf, buf_len, 4, + (uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad }); +} + + +static int +ietf_v1_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len, + uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad) +{ + return ietf_v1_parse_frame_with_varints(buf, buf_len, + 0xAF, 3, (uint64_t *[]) { seqno, pack_tol, upd_mad }); +} + + +static int +ietf_id24_gen_ack_frequency_frame (unsigned char *buf, size_t buf_len, + uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad) +{ + return -1; +} + + +static int +ietf_id24_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len, + uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad) +{ + return -1; +} + + +static unsigned +ietf_v1_ack_frequency_frame_size (uint64_t seqno, uint64_t pack_tol, + uint64_t upd_mad) +{ + return ietf_v1_frame_with_varints_size(4, + (uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad }); +} + + static unsigned ietf_v1_handshake_done_frame_size (void) { @@ -2339,6 +2278,9 @@ const struct parse_funcs lsquic_parse_funcs_ietf_id24 = .pf_gen_handshake_done_frame = ietf_id24_gen_handshake_done_frame, .pf_parse_handshake_done_frame = ietf_id24_parse_handshake_done_frame, .pf_handshake_done_frame_size = ietf_v1_handshake_done_frame_size, + .pf_gen_ack_frequency_frame = ietf_id24_gen_ack_frequency_frame, + .pf_parse_ack_frequency_frame = ietf_id24_parse_ack_frequency_frame, + .pf_ack_frequency_frame_size = ietf_v1_ack_frequency_frame_size, }; @@ -2407,4 +2349,7 @@ const struct parse_funcs lsquic_parse_funcs_ietf_v1 = .pf_gen_handshake_done_frame = ietf_v1_gen_handshake_done_frame, .pf_parse_handshake_done_frame = ietf_v1_parse_handshake_done_frame, .pf_handshake_done_frame_size = ietf_v1_handshake_done_frame_size, + .pf_gen_ack_frequency_frame = ietf_v1_gen_ack_frequency_frame, + .pf_parse_ack_frequency_frame = ietf_v1_parse_ack_frequency_frame, + .pf_ack_frequency_frame_size = ietf_v1_ack_frequency_frame_size, }; diff --git a/src/liblsquic/lsquic_parse_iquic_common.c b/src/liblsquic/lsquic_parse_iquic_common.c index 4351c62..102e772 100644 --- a/src/liblsquic/lsquic_parse_iquic_common.c +++ b/src/liblsquic/lsquic_parse_iquic_common.c @@ -239,7 +239,7 @@ lsquic_is_valid_iquic_hs_packet (const unsigned char *buf, size_t length, } -const enum quic_frame_type lsquic_iquic_byte2type[0x100] = +const enum quic_frame_type lsquic_iquic_byte2type[0x40] = { [0x00] = QUIC_FRAME_PADDING, [0x01] = QUIC_FRAME_PING, @@ -305,198 +305,6 @@ const enum quic_frame_type lsquic_iquic_byte2type[0x100] = [0x3D] = QUIC_FRAME_INVALID, [0x3E] = QUIC_FRAME_INVALID, [0x3F] = QUIC_FRAME_INVALID, - [0x40] = QUIC_FRAME_INVALID, - [0x41] = QUIC_FRAME_INVALID, - [0x42] = QUIC_FRAME_INVALID, - [0x43] = QUIC_FRAME_INVALID, - [0x44] = QUIC_FRAME_INVALID, - [0x45] = QUIC_FRAME_INVALID, - [0x46] = QUIC_FRAME_INVALID, - [0x47] = QUIC_FRAME_INVALID, - [0x48] = QUIC_FRAME_INVALID, - [0x49] = QUIC_FRAME_INVALID, - [0x4A] = QUIC_FRAME_INVALID, - [0x4B] = QUIC_FRAME_INVALID, - [0x4C] = QUIC_FRAME_INVALID, - [0x4D] = QUIC_FRAME_INVALID, - [0x4E] = QUIC_FRAME_INVALID, - [0x4F] = QUIC_FRAME_INVALID, - [0x50] = QUIC_FRAME_INVALID, - [0x51] = QUIC_FRAME_INVALID, - [0x52] = QUIC_FRAME_INVALID, - [0x53] = QUIC_FRAME_INVALID, - [0x54] = QUIC_FRAME_INVALID, - [0x55] = QUIC_FRAME_INVALID, - [0x56] = QUIC_FRAME_INVALID, - [0x57] = QUIC_FRAME_INVALID, - [0x58] = QUIC_FRAME_INVALID, - [0x59] = QUIC_FRAME_INVALID, - [0x5A] = QUIC_FRAME_INVALID, - [0x5B] = QUIC_FRAME_INVALID, - [0x5C] = QUIC_FRAME_INVALID, - [0x5D] = QUIC_FRAME_INVALID, - [0x5E] = QUIC_FRAME_INVALID, - [0x5F] = QUIC_FRAME_INVALID, - [0x60] = QUIC_FRAME_INVALID, - [0x61] = QUIC_FRAME_INVALID, - [0x62] = QUIC_FRAME_INVALID, - [0x63] = QUIC_FRAME_INVALID, - [0x64] = QUIC_FRAME_INVALID, - [0x65] = QUIC_FRAME_INVALID, - [0x66] = QUIC_FRAME_INVALID, - [0x67] = QUIC_FRAME_INVALID, - [0x68] = QUIC_FRAME_INVALID, - [0x69] = QUIC_FRAME_INVALID, - [0x6A] = QUIC_FRAME_INVALID, - [0x6B] = QUIC_FRAME_INVALID, - [0x6C] = QUIC_FRAME_INVALID, - [0x6D] = QUIC_FRAME_INVALID, - [0x6E] = QUIC_FRAME_INVALID, - [0x6F] = QUIC_FRAME_INVALID, - [0x70] = QUIC_FRAME_INVALID, - [0x71] = QUIC_FRAME_INVALID, - [0x72] = QUIC_FRAME_INVALID, - [0x73] = QUIC_FRAME_INVALID, - [0x74] = QUIC_FRAME_INVALID, - [0x75] = QUIC_FRAME_INVALID, - [0x76] = QUIC_FRAME_INVALID, - [0x77] = QUIC_FRAME_INVALID, - [0x78] = QUIC_FRAME_INVALID, - [0x79] = QUIC_FRAME_INVALID, - [0x7A] = QUIC_FRAME_INVALID, - [0x7B] = QUIC_FRAME_INVALID, - [0x7C] = QUIC_FRAME_INVALID, - [0x7D] = QUIC_FRAME_INVALID, - [0x7E] = QUIC_FRAME_INVALID, - [0x7F] = QUIC_FRAME_INVALID, - [0x80] = QUIC_FRAME_INVALID, - [0x81] = QUIC_FRAME_INVALID, - [0x82] = QUIC_FRAME_INVALID, - [0x83] = QUIC_FRAME_INVALID, - [0x84] = QUIC_FRAME_INVALID, - [0x85] = QUIC_FRAME_INVALID, - [0x86] = QUIC_FRAME_INVALID, - [0x87] = QUIC_FRAME_INVALID, - [0x88] = QUIC_FRAME_INVALID, - [0x89] = QUIC_FRAME_INVALID, - [0x8A] = QUIC_FRAME_INVALID, - [0x8B] = QUIC_FRAME_INVALID, - [0x8C] = QUIC_FRAME_INVALID, - [0x8D] = QUIC_FRAME_INVALID, - [0x8E] = QUIC_FRAME_INVALID, - [0x8F] = QUIC_FRAME_INVALID, - [0x90] = QUIC_FRAME_INVALID, - [0x91] = QUIC_FRAME_INVALID, - [0x92] = QUIC_FRAME_INVALID, - [0x93] = QUIC_FRAME_INVALID, - [0x94] = QUIC_FRAME_INVALID, - [0x95] = QUIC_FRAME_INVALID, - [0x96] = QUIC_FRAME_INVALID, - [0x97] = QUIC_FRAME_INVALID, - [0x98] = QUIC_FRAME_INVALID, - [0x99] = QUIC_FRAME_INVALID, - [0x9A] = QUIC_FRAME_INVALID, - [0x9B] = QUIC_FRAME_INVALID, - [0x9C] = QUIC_FRAME_INVALID, - [0x9D] = QUIC_FRAME_INVALID, - [0x9E] = QUIC_FRAME_INVALID, - [0x9F] = QUIC_FRAME_INVALID, - [0xA0] = QUIC_FRAME_INVALID, - [0xA1] = QUIC_FRAME_INVALID, - [0xA2] = QUIC_FRAME_INVALID, - [0xA3] = QUIC_FRAME_INVALID, - [0xA4] = QUIC_FRAME_INVALID, - [0xA5] = QUIC_FRAME_INVALID, - [0xA6] = QUIC_FRAME_INVALID, - [0xA7] = QUIC_FRAME_INVALID, - [0xA8] = QUIC_FRAME_INVALID, - [0xA9] = QUIC_FRAME_INVALID, - [0xAA] = QUIC_FRAME_INVALID, - [0xAB] = QUIC_FRAME_INVALID, - [0xAC] = QUIC_FRAME_INVALID, - [0xAD] = QUIC_FRAME_INVALID, - [0xAE] = QUIC_FRAME_INVALID, - [0xAF] = QUIC_FRAME_INVALID, - [0xB0] = QUIC_FRAME_INVALID, - [0xB1] = QUIC_FRAME_INVALID, - [0xB2] = QUIC_FRAME_INVALID, - [0xB3] = QUIC_FRAME_INVALID, - [0xB4] = QUIC_FRAME_INVALID, - [0xB5] = QUIC_FRAME_INVALID, - [0xB6] = QUIC_FRAME_INVALID, - [0xB7] = QUIC_FRAME_INVALID, - [0xB8] = QUIC_FRAME_INVALID, - [0xB9] = QUIC_FRAME_INVALID, - [0xBA] = QUIC_FRAME_INVALID, - [0xBB] = QUIC_FRAME_INVALID, - [0xBC] = QUIC_FRAME_INVALID, - [0xBD] = QUIC_FRAME_INVALID, - [0xBE] = QUIC_FRAME_INVALID, - [0xBF] = QUIC_FRAME_INVALID, - [0xC0] = QUIC_FRAME_INVALID, - [0xC1] = QUIC_FRAME_INVALID, - [0xC2] = QUIC_FRAME_INVALID, - [0xC3] = QUIC_FRAME_INVALID, - [0xC4] = QUIC_FRAME_INVALID, - [0xC5] = QUIC_FRAME_INVALID, - [0xC6] = QUIC_FRAME_INVALID, - [0xC7] = QUIC_FRAME_INVALID, - [0xC8] = QUIC_FRAME_INVALID, - [0xC9] = QUIC_FRAME_INVALID, - [0xCA] = QUIC_FRAME_INVALID, - [0xCB] = QUIC_FRAME_INVALID, - [0xCC] = QUIC_FRAME_INVALID, - [0xCD] = QUIC_FRAME_INVALID, - [0xCE] = QUIC_FRAME_INVALID, - [0xCF] = QUIC_FRAME_INVALID, - [0xD0] = QUIC_FRAME_INVALID, - [0xD1] = QUIC_FRAME_INVALID, - [0xD2] = QUIC_FRAME_INVALID, - [0xD3] = QUIC_FRAME_INVALID, - [0xD4] = QUIC_FRAME_INVALID, - [0xD5] = QUIC_FRAME_INVALID, - [0xD6] = QUIC_FRAME_INVALID, - [0xD7] = QUIC_FRAME_INVALID, - [0xD8] = QUIC_FRAME_INVALID, - [0xD9] = QUIC_FRAME_INVALID, - [0xDA] = QUIC_FRAME_INVALID, - [0xDB] = QUIC_FRAME_INVALID, - [0xDC] = QUIC_FRAME_INVALID, - [0xDD] = QUIC_FRAME_INVALID, - [0xDE] = QUIC_FRAME_INVALID, - [0xDF] = QUIC_FRAME_INVALID, - [0xE0] = QUIC_FRAME_INVALID, - [0xE1] = QUIC_FRAME_INVALID, - [0xE2] = QUIC_FRAME_INVALID, - [0xE3] = QUIC_FRAME_INVALID, - [0xE4] = QUIC_FRAME_INVALID, - [0xE5] = QUIC_FRAME_INVALID, - [0xE6] = QUIC_FRAME_INVALID, - [0xE7] = QUIC_FRAME_INVALID, - [0xE8] = QUIC_FRAME_INVALID, - [0xE9] = QUIC_FRAME_INVALID, - [0xEA] = QUIC_FRAME_INVALID, - [0xEB] = QUIC_FRAME_INVALID, - [0xEC] = QUIC_FRAME_INVALID, - [0xED] = QUIC_FRAME_INVALID, - [0xEE] = QUIC_FRAME_INVALID, - [0xEF] = QUIC_FRAME_INVALID, - [0xF0] = QUIC_FRAME_INVALID, - [0xF1] = QUIC_FRAME_INVALID, - [0xF2] = QUIC_FRAME_INVALID, - [0xF3] = QUIC_FRAME_INVALID, - [0xF4] = QUIC_FRAME_INVALID, - [0xF5] = QUIC_FRAME_INVALID, - [0xF6] = QUIC_FRAME_INVALID, - [0xF7] = QUIC_FRAME_INVALID, - [0xF8] = QUIC_FRAME_INVALID, - [0xF9] = QUIC_FRAME_INVALID, - [0xFA] = QUIC_FRAME_INVALID, - [0xFB] = QUIC_FRAME_INVALID, - [0xFC] = QUIC_FRAME_INVALID, - [0xFD] = QUIC_FRAME_INVALID, - [0xFE] = QUIC_FRAME_INVALID, - [0xFF] = QUIC_FRAME_INVALID, }; diff --git a/src/liblsquic/lsquic_send_ctl.h b/src/liblsquic/lsquic_send_ctl.h index b2fe6c4..c4d7685 100644 --- a/src/liblsquic/lsquic_send_ctl.h +++ b/src/liblsquic/lsquic_send_ctl.h @@ -381,4 +381,6 @@ lsquic_send_ctl_cidlen_change (struct lsquic_send_ctl *, void lsquic_send_ctl_begin_optack_detection (struct lsquic_send_ctl *); +#define lsquic_send_ctl_n_unacked(ctl_) ((ctl_)->sc_n_in_flight_retx) + #endif diff --git a/src/liblsquic/lsquic_trans_params.c b/src/liblsquic/lsquic_trans_params.c index ab780b2..a8dc0fd 100644 --- a/src/liblsquic/lsquic_trans_params.c +++ b/src/liblsquic/lsquic_trans_params.c @@ -51,6 +51,7 @@ tpi_val_2_enum (uint64_t tpi_val) case 0xC37: return TPI_QUANTUM_READINESS; #endif case 0x1057: return TPI_LOSS_BITS; + case 0xDE1A: return TPI_MIN_ACK_DELAY; default: return INT_MAX; } } @@ -77,6 +78,7 @@ static const unsigned short enum_2_tpi_val[LAST_TPI + 1] = [TPI_QUANTUM_READINESS] = 0xC37, #endif [TPI_LOSS_BITS] = 0x1057, + [TPI_MIN_ACK_DELAY] = 0xDE1A, }; @@ -101,6 +103,7 @@ static const char * const tpi2str[LAST_TPI + 1] = [TPI_QUANTUM_READINESS] = "quantum_readiness", #endif [TPI_LOSS_BITS] = "loss_bits", + [TPI_MIN_ACK_DELAY] = "min_ack_delay", }; @@ -134,6 +137,13 @@ static const uint64_t max_vals[MAX_NUMERIC_TPI + 1] = [TPI_MAX_ACK_DELAY] = TP_MAX_MAX_ACK_DELAY, [TPI_ACTIVE_CONNECTION_ID_LIMIT] = VINT_MAX_VALUE, [TPI_LOSS_BITS] = 1, + [TPI_MIN_ACK_DELAY] = (1u << 24) - 1u, +}; + + +static const uint64_t min_vals[MAX_NUMERIC_TPI + 1] = +{ + [TPI_MIN_ACK_DELAY] = 1, }; @@ -203,16 +213,24 @@ lsquic_tp_encode (const struct transport_params *params, int is_server, if (tpi > MAX_NUM_WITH_DEF_TPI || params->tp_numerics[tpi] != def_vals[tpi]) { - if (params->tp_numerics[tpi] <= max_vals[tpi]) + if (params->tp_numerics[tpi] >= min_vals[tpi] + && params->tp_numerics[tpi] <= max_vals[tpi]) { bits[tpi] = vint_val2bits(params->tp_numerics[tpi]); need += 4 + (1 << bits[tpi]); } + else if (params->tp_numerics[tpi] > max_vals[tpi]) + { + LSQ_DEBUG("numeric value of %s is too large (%"PRIu64" vs " + "maximum of %"PRIu64")", tpi2str[tpi], + params->tp_numerics[tpi], max_vals[tpi]); + return -1; + } else { - LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum " - "of %"PRIu64")", params->tp_numerics[tpi], - max_vals[tpi]); + LSQ_DEBUG("numeric value of %s is too small (%"PRIu64" vs " + "minimum " "of %"PRIu64")", + tpi2str[tpi], params->tp_numerics[tpi], min_vals[tpi]); return -1; } } @@ -278,6 +296,7 @@ lsquic_tp_encode (const struct transport_params *params, int is_server, case TPI_MAX_ACK_DELAY: case TPI_ACTIVE_CONNECTION_ID_LIMIT: case TPI_LOSS_BITS: + case TPI_MIN_ACK_DELAY: WRITE_UINT_TO_P(1 << bits[tpi], 16); vint_write(p, params->tp_numerics[tpi], bits[tpi], 1 << bits[tpi]); @@ -392,6 +411,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz, case TPI_MAX_ACK_DELAY: case TPI_ACTIVE_CONNECTION_ID_LIMIT: case TPI_LOSS_BITS: + case TPI_MIN_ACK_DELAY: switch (len) { case 1: @@ -403,9 +423,16 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz, { if (params->tp_numerics[tpi] > max_vals[tpi]) { - LSQ_DEBUG("numeric value of parameter 0x%X is too " - "large (%"PRIu64" vs maximum of %"PRIu64, - param_id, params->tp_numerics[tpi], max_vals[tpi]); + LSQ_DEBUG("numeric value of %s is too large " + "(%"PRIu64" vs maximum of %"PRIu64, tpi2str[tpi], + params->tp_numerics[tpi], max_vals[tpi]); + return -1; + } + else if (params->tp_numerics[tpi] < min_vals[tpi]) + { + LSQ_DEBUG("numeric value of %s is too small " + "(%"PRIu64" vs minimum of %"PRIu64, tpi2str[tpi], + params->tp_numerics[tpi], min_vals[tpi]); return -1; } break; @@ -502,6 +529,17 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz, if (p != end) return -1; + if ((params->tp_set & (1 << TPI_MIN_ACK_DELAY)) + && params->tp_numerics[TPI_MIN_ACK_DELAY] + > params->tp_numerics[TPI_MAX_ACK_DELAY] * 1000) + { + LSQ_DEBUG("min_ack_delay (%"PRIu64" usec) is larger than " + "max_ack_delay (%"PRIu64" ms)", + params->tp_numerics[TPI_MIN_ACK_DELAY], + params->tp_numerics[TPI_MAX_ACK_DELAY]); + return -1; + } + return (int) (end - buf); #undef EXPECT_LEN } @@ -517,7 +555,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz) char addr_str[INET6_ADDRSTRLEN]; for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi) - if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)) + if (params->tp_set & (1 << tpi)) { nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64, (buf + sz > end) << 1, "; ", tpi2str[tpi], diff --git a/src/liblsquic/lsquic_trans_params.h b/src/liblsquic/lsquic_trans_params.h index cc33862..d297178 100644 --- a/src/liblsquic/lsquic_trans_params.h +++ b/src/liblsquic/lsquic_trans_params.h @@ -32,6 +32,7 @@ enum transport_param_id /* * Numeric transport parameters without default values: */ + TPI_MIN_ACK_DELAY, TPI_LOSS_BITS, MAX_NUMERIC_TPI = TPI_LOSS_BITS, /* diff --git a/test/test_common.c b/test/test_common.c index a3aa3df..37313ac 100644 --- a/test/test_common.c +++ b/test/test_common.c @@ -1846,6 +1846,11 @@ set_engine_option (struct lsquic_engine_settings *settings, settings->es_handshake_to = atoi(val); return 0; } + if (0 == strncmp(name, "delayed_acks", 12)) + { + settings->es_delayed_acks = atoi(val); + return 0; + } break; case 13: if (0 == strncmp(name, "support_tcid0", 13))