Add experimental support for delayed ACKs extension

This commit is contained in:
Dmitri Tikhonov 2020-02-21 14:26:25 -05:00
parent df25d34a5e
commit feca77f50d
21 changed files with 465 additions and 427 deletions

View file

@ -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

View file

@ -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
-----------------

View file

@ -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 */

View file

@ -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(&params, 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, &params_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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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

View file

@ -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]);

View file

@ -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;

View file

@ -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 */

View file

@ -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,

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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

View file

@ -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],

View file

@ -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,
/*

View file

@ -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))