diff --git a/examples/client.cc b/examples/client.cc index 81647de6d1c9874b5f47935abb9024158e29f023..b7c9eb9830b370d22ef7f157a9a1ca31a7c77cbc 100644 --- a/examples/client.cc +++ b/examples/client.cc @@ -220,18 +220,17 @@ void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { namespace { void retransmitcb(struct ev_loop *loop, ev_timer *w, int revents) { auto c = static_cast<Client *>(w->data); + auto conn = c->conn(); + auto now = util::timestamp(); - if (c->on_write(true) != 0) { + if (ngtcp2_conn_earliest_expiry(conn) < now + 1000000 && + c->on_write(true) != 0) { c->disconnect(); + return; } -} -} // namespace -namespace { -void ackcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto c = static_cast<Client *>(w->data); - - if (c->on_write() != 0) { + if (ngtcp2_conn_ack_delay_expiry(conn) < now + 1000000 && + c->on_write() != 0) { c->disconnect(); } } @@ -269,8 +268,6 @@ Client::Client(struct ev_loop *loop, SSL_CTX *ssl_ctx) timer_.data = this; ev_timer_init(&rttimer_, retransmitcb, 0., 0.); rttimer_.data = this; - ev_timer_init(&acktimer_, ackcb, 0., 0.); - acktimer_.data = this; ev_signal_init(&sigintev_, siginthandler, SIGINT); } @@ -284,7 +281,6 @@ void Client::disconnect() { disconnect(0); } void Client::disconnect(int liberr) { config.tx_loss_prob = 0; - ev_timer_stop(loop_, &acktimer_); ev_timer_stop(loop_, &rttimer_); ev_timer_stop(loop_, &timer_); @@ -998,6 +994,9 @@ int Client::on_write(bool retransmit) { return rv; } } + + schedule_retransmit(); + return 0; } if (!ngtcp2_conn_get_handshake_completed(conn_)) { @@ -1116,33 +1115,24 @@ void Client::schedule_retransmit() { ev_tstamp t; auto now = util::timestamp(); - auto expiry = ngtcp2_conn_earliest_expiry(conn_); - if (expiry) { - ev_timer_stop(loop_, &rttimer_); + auto expiry = std::min(ngtcp2_conn_earliest_expiry(conn_), + ngtcp2_conn_ack_delay_expiry(conn_)); - if (now >= expiry) { - t = 0.; - } else { - t = static_cast<ev_tstamp>(expiry - now) / 1000000000; - } + if (expiry == UINT64_MAX) { ev_timer_stop(loop_, &rttimer_); - ev_timer_set(&rttimer_, t, 0.); - ev_timer_start(loop_, &rttimer_); + return; } - expiry = ngtcp2_conn_ack_delay_expiry(conn_); - if (expiry) { - ev_timer_stop(loop_, &acktimer_); + ev_timer_stop(loop_, &rttimer_); - if (now >= expiry) { - t = 0.; - } else { - t = static_cast<ev_tstamp>(expiry - now) / 1000000000; - } - ev_timer_stop(loop_, &acktimer_); - ev_timer_set(&acktimer_, t, 0.); - ev_timer_start(loop_, &acktimer_); + if (now >= expiry) { + t = 0.; + } else { + t = static_cast<ev_tstamp>(expiry - now) / 1000000000; } + ev_timer_stop(loop_, &rttimer_); + ev_timer_set(&rttimer_, t, 0.); + ev_timer_start(loop_, &rttimer_); } int Client::write_client_handshake(const uint8_t *data, size_t datalen) { diff --git a/examples/client.h b/examples/client.h index c75e8987b3db004e3fba778bb0caacbf61045341..d5f24b69e72232376148cb3f93332f43135f06d5 100644 --- a/examples/client.h +++ b/examples/client.h @@ -199,7 +199,6 @@ private: ev_io stdinrev_; ev_timer timer_; ev_timer rttimer_; - ev_timer acktimer_; ev_signal sigintev_; struct ev_loop *loop_; SSL_CTX *ssl_ctx_; diff --git a/examples/server.cc b/examples/server.cc index 6c097d93b231bb03a5266a122e908e98fe63d045..ee798e14a81ebfc0872b39730275353f7fc61ca3 100644 --- a/examples/server.cc +++ b/examples/server.cc @@ -500,17 +500,37 @@ void retransmitcb(struct ev_loop *loop, ev_timer *w, int revents) { auto h = static_cast<Handler *>(w->data); auto s = h->server(); + auto conn = h->conn(); + auto now = util::timestamp(); - rv = h->on_write(true); - switch (rv) { - case 0: - case NETWORK_ERR_CLOSE_WAIT: - break; - case NETWORK_ERR_SEND_NON_FATAL: - s->start_wev(); - break; - default: - s->remove(h); + if (ngtcp2_conn_earliest_expiry(conn) < now + 1000000) { + rv = h->on_write(true); + switch (rv) { + case 0: + case NETWORK_ERR_CLOSE_WAIT: + return; + case NETWORK_ERR_SEND_NON_FATAL: + s->start_wev(); + return; + default: + s->remove(h); + return; + } + } + + if (ngtcp2_conn_ack_delay_expiry(conn) < now + 1000000) { + rv = h->on_write(); + switch (rv) { + case 0: + case NETWORK_ERR_CLOSE_WAIT: + return; + case NETWORK_ERR_SEND_NON_FATAL: + s->start_wev(); + return; + default: + s->remove(h); + return; + } } } } // namespace @@ -1362,6 +1382,9 @@ int Handler::on_write(bool retransmit) { return rv; } } + + schedule_retransmit(); + return 0; } if (!ngtcp2_conn_get_handshake_completed(conn_)) { @@ -1567,8 +1590,9 @@ int Handler::send_conn_close() { } void Handler::schedule_retransmit() { - auto expiry = ngtcp2_conn_earliest_expiry(conn_); - if (expiry == 0) { + auto expiry = std::min(ngtcp2_conn_earliest_expiry(conn_), + ngtcp2_conn_ack_delay_expiry(conn_)); + if (expiry == UINT64_MAX) { ev_timer_stop(loop_, &rttimer_); return; } diff --git a/lib/ngtcp2_acktr.c b/lib/ngtcp2_acktr.c index 02e0f4515e989881a58d702ed28ec19510d9696b..dc821330723d7256747f2437f2a8970e083a9129 100644 --- a/lib/ngtcp2_acktr.c +++ b/lib/ngtcp2_acktr.c @@ -66,8 +66,7 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_mem *mem) { acktr->nack = 0; acktr->last_hs_ack_pkt_num = UINT64_MAX; acktr->flags = NGTCP2_ACKTR_FLAG_NONE; - acktr->last_unprotected_added = 0; - acktr->last_added = 0; + acktr->first_unacked_ts = 0; return 0; } @@ -123,17 +122,11 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent, if (ent->unprotected) { /* Should be sent in both protected and unprotected ACK */ acktr->flags |= NGTCP2_ACKTR_FLAG_ACTIVE_ACK; - if (!acktr->last_unprotected_added) { - acktr->last_unprotected_added = ts; - } - if (!acktr->last_added) { - acktr->last_added = ts; - } } else { acktr->flags |= NGTCP2_ACKTR_FLAG_ACTIVE_ACK_PROTECTED; - if (!acktr->last_added) { - acktr->last_added = ts; - } + } + if (acktr->first_unacked_ts == UINT64_MAX) { + acktr->first_unacked_ts = ts; } } @@ -363,20 +356,17 @@ int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr, void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr, int unprotected) { if (unprotected) { acktr->flags &= (uint8_t)~NGTCP2_ACKTR_FLAG_ACTIVE_ACK_UNPROTECTED; - acktr->last_unprotected_added = 0; } else { acktr->flags &= (uint8_t)~NGTCP2_ACKTR_FLAG_ACTIVE_ACK_PROTECTED; - acktr->last_added = 0; + acktr->first_unacked_ts = UINT64_MAX; } } int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr, int unprotected, uint64_t max_ack_delay, ngtcp2_tstamp ts) { if (unprotected) { - return (acktr->flags & NGTCP2_ACKTR_FLAG_ACTIVE_ACK_UNPROTECTED) && - acktr->last_unprotected_added && - acktr->last_unprotected_added + max_ack_delay <= ts; + return acktr->flags & NGTCP2_ACKTR_FLAG_ACTIVE_ACK_UNPROTECTED; } return (acktr->flags & NGTCP2_ACKTR_FLAG_ACTIVE_ACK_PROTECTED) && - acktr->last_added && acktr->last_added + max_ack_delay <= ts; + acktr->first_unacked_ts <= ts - max_ack_delay; } diff --git a/lib/ngtcp2_acktr.h b/lib/ngtcp2_acktr.h index b6c3f3d7836059911f18808c8963e817dfbf4c8b..06ecac25c0bd0a62b7628bcd3c4bcf9b45a5e9d5 100644 --- a/lib/ngtcp2_acktr.h +++ b/lib/ngtcp2_acktr.h @@ -117,15 +117,9 @@ typedef struct { uint64_t last_hs_ack_pkt_num; /* flags is bitwise OR of zero, or more of ngtcp2_ack_flag. */ uint8_t flags; - /* last_unprotected_added is timestamp when unprotected - ngtcp2_acktr_entry is added first time after the last outgoing - ACK frame. */ - /* TODO This should be first_unprotected_unacked_ts */ - ngtcp2_tstamp last_unprotected_added; - /* last_added is timestamp when ngtcp2_acktr_entry is added first - time after the last outgoing ACK frame. */ - /* TODO This should be first_unacked_ts */ - ngtcp2_tstamp last_added; + /* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added + first time after the last outgoing protected ACK frame. */ + ngtcp2_tstamp first_unacked_ts; } ngtcp2_acktr; /* diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index 4cf137947fa456ab85481a236029a817fb49b5cb..ff7faf798040798541214c3b6f9516c1ebc68e5b 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -373,6 +373,22 @@ static int conn_ensure_ack_blks(ngtcp2_conn *conn, ngtcp2_frame **pfr, return 0; } +/* + * conn_compute_ack_delay computes ACK delay for outgoing protected + * ACK. + */ +static uint64_t conn_compute_ack_delay(ngtcp2_conn *conn) { + uint64_t ack_delay; + + if (conn->rcs.min_rtt == 0) { + return NGTCP2_DEFAULT_ACK_DELAY; + } + + ack_delay = (uint64_t)(conn->rcs.smoothed_rtt / 4); + + return ngtcp2_min(NGTCP2_DEFAULT_ACK_DELAY, ack_delay); +} + /* * conn_create_ack_frame creates ACK frame, and assigns its pointer to * |*pfr| if there are any received packets to acknowledge. If there @@ -407,12 +423,7 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, size_t num_blks_max = 8; size_t blk_idx; int rv; - uint64_t max_ack_delay = NGTCP2_DEFAULT_ACK_DELAY; - - if (conn->rcs.min_rtt) { - max_ack_delay = - ngtcp2_min(max_ack_delay, (uint64_t)(conn->rcs.smoothed_rtt / 4)); - } + uint64_t max_ack_delay = conn_compute_ack_delay(conn); if (!ngtcp2_acktr_require_active_ack(&conn->acktr, unprotected, max_ack_delay, ts)) { @@ -425,9 +436,8 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, ; } if (*prpkt == NULL) { - conn->acktr.last_unprotected_added = 0; if (!unprotected) { - conn->acktr.last_added = 0; + conn->acktr.first_unacked_ts = UINT64_MAX; } return 0; } @@ -4035,31 +4045,17 @@ int ngtcp2_conn_update_rx_keys(ngtcp2_conn *conn, const uint8_t *key, } ngtcp2_tstamp ngtcp2_conn_earliest_expiry(ngtcp2_conn *conn) { - return conn->rcs.loss_detection_alarm; + if (conn->rcs.loss_detection_alarm) { + return conn->rcs.loss_detection_alarm; + } + return UINT64_MAX; } ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { - if (ngtcp2_conn_get_handshake_completed(conn)) { - if (!conn->acktr.last_added) { - return 0; - } - return conn->acktr.last_added + NGTCP2_DEFAULT_ACK_DELAY; - } - - if (!conn->acktr.last_added) { - if (!conn->acktr.last_unprotected_added) { - return 0; - } - return conn->acktr.last_unprotected_added + NGTCP2_DEFAULT_ACK_DELAY; + if (conn->acktr.first_unacked_ts == UINT64_MAX) { + return UINT64_MAX; } - - if (!conn->acktr.last_unprotected_added) { - return conn->acktr.last_added + NGTCP2_DEFAULT_ACK_DELAY; - } - - return ngtcp2_min(conn->acktr.last_added, - conn->acktr.last_unprotected_added) + - NGTCP2_DEFAULT_ACK_DELAY; + return conn->acktr.first_unacked_ts + conn_compute_ack_delay(conn); } int ngtcp2_pkt_chain_new(ngtcp2_pkt_chain **ppc, const uint8_t *pkt,