diff --git a/CHANGELOG b/CHANGELOG index 001fc7944..aa1256864 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +2020-08-06 + - 2.19.4 + - [BUGFIX] Do not return an oversize MTU probe to connection twice. + - [FEATURE] Delayed Acks updated to latest draft. Still experimental. + - Minor code cleanup in IETF full connection. + 2020-08-04 - 2.19.3 - [BUGFIX] Regression in 2.19.1 that breaks Q050 diff --git a/docs/conf.py b/docs/conf.py index d27e037c6..a3dd3a9c2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ # The short X.Y version version = u'2.19' # The full version, including alpha/beta/rc tags -release = u'2.19.3' +release = u'2.19.4' # -- General configuration --------------------------------------------------- diff --git a/include/lsquic.h b/include/lsquic.h index 4a6bc3481..bb6ff3170 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -25,7 +25,7 @@ extern "C" { #define LSQUIC_MAJOR_VERSION 2 #define LSQUIC_MINOR_VERSION 19 -#define LSQUIC_PATCH_VERSION 3 +#define LSQUIC_PATCH_VERSION 4 /** * Engine flags: diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index ab0e995b1..5820c58ec 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -2292,6 +2292,7 @@ send_batch (lsquic_engine_t *engine, const struct send_batch_ctx *sb_ctx, LSQ_DEBUG("restart batch starting at packet #%u", skip); goto restart_batch; } + n_sent = n_to_send; } else close_conn_on_send_error(engine, sb_ctx, i, e_val); diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index a582ff608..31b165ebf 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -143,6 +143,7 @@ enum more_flags MF_VALIDATE_PATH = 1 << 0, MF_NOPROG_TIMEOUT = 1 << 1, MF_CHECK_MTU_PROBE = 1 << 2, + MF_IGNORE_MISSING = 1 << 3, }; @@ -314,7 +315,6 @@ struct conn_path */ COP_GOT_NONPROB = 1 << 2, } cop_flags; - unsigned short cop_max_plpmtu; unsigned char cop_n_chals; unsigned char cop_cce_idx; struct dplpmtud_state cop_dplpmtud; @@ -1692,7 +1692,7 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn, } lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w); packet_out->po_regen_sz += w; - if (has_missing) + if (has_missing && !(conn->ifc_mflags & MF_IGNORE_MISSING)) conn->ifc_flags |= IFC_ACK_HAD_MISS; else conn->ifc_flags &= ~IFC_ACK_HAD_MISS; @@ -2232,6 +2232,8 @@ generate_stream_blocked_frame (struct ietf_full_conn *conn, ABORT_ERROR("Generating STREAM_BLOCKED frame failed"); return 0; } + LSQ_DEBUG("generated %d-byte STREAM_BLOCKED " + "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated %d-byte STREAM_BLOCKED " "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); if (0 != lsquic_packet_out_add_frame(packet_out, conn->ifc_pub.mm, 0, @@ -4042,15 +4044,37 @@ generate_handshake_done_frame (struct ietf_full_conn *conn, } +static unsigned +packet_tolerance (float avg_acked) +{ + if (avg_acked < 3) + return 2; + if (avg_acked < 10) + return 4; + if (avg_acked < 20) + return 8; + if (avg_acked < 40) + return 16; + if (avg_acked < 80) + return 32; + return 64; +} + + 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; + /* We tell the peer to ignore reordering because we skip packet numbers to + * detect optimistic ACK attacks. + */ + const int ignore = 1; need = conn->ifc_conn.cn_pf->pf_ack_frequency_frame_size( - conn->ifc_ack_freq_seqno, 2, ACK_TIMEOUT); + conn->ifc_ack_freq_seqno, conn->ifc_last_pack_tol, + conn->ifc_max_peer_ack_usec); packet_out = get_writeable_packet(conn, need); if (!packet_out) { @@ -4058,12 +4082,12 @@ generate_ack_frequency_frame (struct ietf_full_conn *conn, lsquic_time_t unused) return; } - conn->ifc_last_pack_tol = conn->ifc_ias.avg_acked; + conn->ifc_last_pack_tol = packet_tolerance(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); + conn->ifc_max_peer_ack_usec, ignore); if (sz < 0) { ABORT_ERROR("gen_ack_frequency_frame failed"); @@ -4077,6 +4101,9 @@ generate_ack_frequency_frame (struct ietf_full_conn *conn, lsquic_time_t unused) } lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, sz); packet_out->po_frame_types |= QUIC_FTBIT_ACK_FREQUENCY; + LSQ_DEBUG("Generated ACK_FREQUENCY(seqno: %u; pack_tol: %u; " + "upd: %u; ignore: %d)", conn->ifc_ack_freq_seqno, + conn->ifc_last_pack_tol, conn->ifc_max_peer_ack_usec, ignore); ++conn->ifc_ack_freq_seqno; conn->ifc_send_flags &= ~SF_SEND_ACK_FREQUENCY; } @@ -4365,21 +4392,25 @@ static void update_target_packet_tolerance (struct ietf_full_conn *conn, const unsigned n_newly_acked) { + unsigned tol; + update_ema(&conn->ifc_ias.avg_n_acks, conn->ifc_ias.n_acks); update_ema(&conn->ifc_ias.avg_acked, n_newly_acked); + + tol = packet_tolerance(conn->ifc_ias.avg_acked); LSQ_DEBUG("packtol logic: %u ACK frames (avg: %.2f), %u newly acked " - "(avg: %.1f), last sent %u", conn->ifc_ias.n_acks, + "(avg: %.1f), last sent %u, would-be tol: %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); + conn->ifc_last_pack_tol, 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) + && tol > 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) + && (float) tol < (float) conn->ifc_last_pack_tol * 3 / 4) { LSQ_DEBUG("old packet tolerance target: %u, schedule ACK_FREQUENCY " "decrease", conn->ifc_last_pack_tol); @@ -5808,7 +5839,7 @@ 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; + int parsed_len, ignore; if (!(conn->ifc_flags & IFC_DELAYED_ACKS)) { @@ -5818,15 +5849,16 @@ process_ack_frequency_frame (struct ietf_full_conn *conn, } parsed_len = conn->ifc_conn.cn_pf->pf_parse_ack_frequency_frame(p, len, - &seqno, &pack_tol, &upd_mad); + &seqno, &pack_tol, &upd_mad, &ignore); 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); + "pack_tol: %"PRIu64"; upd: %"PRIu64"; ignore: %d) frame in", seqno, + pack_tol, upd_mad, ignore); LSQ_DEBUG("ACK_FREQUENCY(seqno: %"PRIu64"; pack_tol: %"PRIu64"; " - "upd: %"PRIu64") frame in", seqno, pack_tol, upd_mad); + "upd: %"PRIu64"; ignore: %d) frame in", seqno, pack_tol, upd_mad, + ignore); if (pack_tol == 0) { @@ -5851,6 +5883,14 @@ process_ack_frequency_frame (struct ietf_full_conn *conn, /* TODO: do something with max ack delay update */ + if (ignore) + { + conn->ifc_mflags |= MF_IGNORE_MISSING; + conn->ifc_flags &= ~IFC_ACK_HAD_MISS; + } + else + conn->ifc_mflags &= ~MF_IGNORE_MISSING; + return parsed_len; } diff --git a/src/liblsquic/lsquic_parse.h b/src/liblsquic/lsquic_parse.h index 339dce60e..7d2012fd9 100644 --- a/src/liblsquic/lsquic_parse.h +++ b/src/liblsquic/lsquic_parse.h @@ -310,13 +310,13 @@ struct parse_funcs (*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); + uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad, int ignore); 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); + uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad, int *ignore); unsigned (*pf_ack_frequency_frame_size) (uint64_t seqno, uint64_t pack_tol, - uint64_t upd_mad); + uint64_t upd_mad /* Don't need to pass `ignore' */); int (*pf_gen_timestamp_frame) (unsigned char *buf, size_t buf_len, uint64_t); int diff --git a/src/liblsquic/lsquic_parse_ietf_v1.c b/src/liblsquic/lsquic_parse_ietf_v1.c index db566a708..2d44c34e2 100644 --- a/src/liblsquic/lsquic_parse_ietf_v1.c +++ b/src/liblsquic/lsquic_parse_ietf_v1.c @@ -2066,20 +2066,38 @@ 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) + uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad, int ignore) { - return ietf_v1_gen_frame_with_varints(buf, buf_len, 4, + int sz; + + sz = ietf_v1_gen_frame_with_varints(buf, buf_len, 4, (uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad }); + if (sz > 0 && (size_t) sz < buf_len) + { + buf[sz++] = !!ignore; + return sz; + } + else + return -1; } 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) + uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad, int *ignore) { - return ietf_v1_parse_frame_with_varints(buf, buf_len, + int sz; + + sz = ietf_v1_parse_frame_with_varints(buf, buf_len, FRAME_TYPE_ACK_FREQUENCY, 3, (uint64_t *[]) { seqno, pack_tol, upd_mad }); + if (sz > 0 && (size_t) sz < buf_len && buf[sz] < 2) + { + *ignore = buf[sz++]; + return sz; + } + else + return -1; } @@ -2087,7 +2105,7 @@ 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, + return 1 + ietf_v1_frame_with_varints_size(4, (uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad }); }