From ea0207e2c5b784ef7345c1b1a10b78e42774cad6 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> Date: Thu, 23 May 2019 16:27:28 +0900 Subject: [PATCH] Add function to cancel expired ACK delay timer --- doc/programmers-guide.rst | 1 + examples/client.cc | 1 + examples/server.cc | 1 + lib/includes/ngtcp2/ngtcp2.h | 11 +++++++++++ lib/ngtcp2_acktr.c | 6 +++--- lib/ngtcp2_acktr.h | 3 +++ lib/ngtcp2_conn.c | 27 ++++++++++++++++++++++----- 7 files changed, 42 insertions(+), 8 deletions(-) diff --git a/doc/programmers-guide.rst b/doc/programmers-guide.rst index 3d504064..8a4bed47 100644 --- a/doc/programmers-guide.rst +++ b/doc/programmers-guide.rst @@ -271,6 +271,7 @@ timestamp is equal to or larger than the value returned from (or `ngtcp2_conn_write_handshake()` if handshake has not completed yet). If the current timestamp is equal to or larger than the value returned from `ngtcp2_conn_ack_delay_expiry()`, it has to call +`ngtcp2_conn_cancel_expired_ack_delay_timer()` and `ngtcp2_conn_write_pkt()` (or `ngtcp2_conn_write_handshake()` if handshake has not completed yet). After calling these functions, new expiry will be set. The application should call diff --git a/examples/client.cc b/examples/client.cc index 6041c1a2..7cf29c3c 100644 --- a/examples/client.cc +++ b/examples/client.cc @@ -361,6 +361,7 @@ void retransmitcb(struct ev_loop *loop, ev_timer *w, int revents) { } if (ngtcp2_conn_ack_delay_expiry(conn) <= now) { + ngtcp2_conn_cancel_expired_ack_delay_timer(conn, now); rv = c->on_write(); if (rv != 0) { goto fail; diff --git a/examples/server.cc b/examples/server.cc index 4556adb1..66099927 100644 --- a/examples/server.cc +++ b/examples/server.cc @@ -835,6 +835,7 @@ void retransmitcb(struct ev_loop *loop, ev_timer *w, int revents) { if (!config.quiet) { std::cerr << "Delayed ACK timer expired" << std::endl; } + ngtcp2_conn_cancel_expired_ack_delay_timer(conn, now); rv = h->on_write(); switch (rv) { case 0: diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index 9428fd5f..8b6bb4c9 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -2030,6 +2030,7 @@ ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn); * * `ngtcp2_conn_ack_delay_expiry` returns the expiry time point of * delayed protected ACK. Application should call + * ngtcp2_conn_cancel_expired_ack_delay_timer() and * `ngtcp2_conn_write_pkt` (or `ngtcp2_conn_write_handshake` if * handshake has not finished yet) when it expires. It returns * UINT64_MAX if there is no expiry. @@ -2046,6 +2047,16 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn); */ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_cancel_expired_ack_delay_timer` stops expired ACK + * delay timer. |ts| is the current time. This function must be + * called when ngtcp2_conn_ack_delay_expiry() <= ts. + */ +NGTCP2_EXTERN void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, + ngtcp2_tstamp ts); + /** * @function * diff --git a/lib/ngtcp2_acktr.c b/lib/ngtcp2_acktr.c index e7403db6..494e4cd6 100644 --- a/lib/ngtcp2_acktr.c +++ b/lib/ngtcp2_acktr.c @@ -316,15 +316,15 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) { void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) { acktr->flags &= (uint16_t) ~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK | - NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK); + NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK | + NGTCP2_ACKTR_FLAG_CANCEL_TIMER); acktr->first_unacked_ts = UINT64_MAX; acktr->rx_npkt = 0; } int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr, uint64_t max_ack_delay, ngtcp2_tstamp ts) { - return (acktr->flags & NGTCP2_ACKTR_FLAG_ACTIVE_ACK) && - acktr->first_unacked_ts <= ts - max_ack_delay; + return acktr->first_unacked_ts <= ts - max_ack_delay; } void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) { diff --git a/lib/ngtcp2_acktr.h b/lib/ngtcp2_acktr.h index 35e00d76..19864203 100644 --- a/lib/ngtcp2_acktr.h +++ b/lib/ngtcp2_acktr.h @@ -108,6 +108,9 @@ typedef enum { acknowledgement for ACK which acknowledges the last handshake packet from client (which contains TLSv1.3 Finished message). */ NGTCP2_ACKTR_FLAG_ACK_FINISHED_ACK = 0x80, + /* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is + expired and canceled. */ + NGTCP2_ACKTR_FLAG_CANCEL_TIMER = 0x0100, } ngtcp2_acktr_flag; /* diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index cafd051d..ba886462 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -1754,8 +1754,7 @@ static ssize_t conn_write_handshake_ack_pkt(ngtcp2_conn *conn, uint8_t *dest, * Initial and Handshake packet. */ static ssize_t conn_write_handshake_ack_pkts(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, - ngtcp2_tstamp ts) { + size_t destlen, ngtcp2_tstamp ts) { ssize_t res = 0, nwrite = 0; int require_padding; @@ -7511,15 +7510,18 @@ ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { ngtcp2_acktr *acktr = &conn->pktns.acktr; ngtcp2_tstamp ts = UINT64_MAX, t; - if (in_acktr->first_unacked_ts != UINT64_MAX) { + if (!(in_acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && + in_acktr->first_unacked_ts != UINT64_MAX) { t = in_acktr->first_unacked_ts + NGTCP2_HS_ACK_DELAY; ts = ngtcp2_min(ts, t); } - if (hs_acktr->first_unacked_ts != UINT64_MAX) { + if (!(hs_acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && + hs_acktr->first_unacked_ts != UINT64_MAX) { t = hs_acktr->first_unacked_ts + NGTCP2_HS_ACK_DELAY; ts = ngtcp2_min(ts, t); } - if (acktr->first_unacked_ts != UINT64_MAX) { + if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && + acktr->first_unacked_ts != UINT64_MAX) { t = acktr->first_unacked_ts + conn_compute_ack_delay(conn); ts = ngtcp2_min(ts, t); } @@ -7532,6 +7534,21 @@ ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) { return ngtcp2_min(t1, t2); } +static void acktr_cancel_expired_ack_delay_timer(ngtcp2_acktr *acktr, + ngtcp2_tstamp ts) { + if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && + acktr->first_unacked_ts <= ts) { + acktr->flags |= NGTCP2_ACKTR_FLAG_CANCEL_TIMER; + } +} + +void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, + ngtcp2_tstamp ts) { + acktr_cancel_expired_ack_delay_timer(&conn->in_pktns.acktr, ts); + acktr_cancel_expired_ack_delay_timer(&conn->hs_pktns.acktr, ts); + acktr_cancel_expired_ack_delay_timer(&conn->pktns.acktr, ts); +} + /* * settings_copy_from_transport_params translates * ngtcp2_transport_params to ngtcp2_settings. -- GitLab