diff options
Diffstat (limited to 'deps/ngtcp2/lib/ngtcp2_conn.c')
-rw-r--r-- | deps/ngtcp2/lib/ngtcp2_conn.c | 1454 |
1 files changed, 925 insertions, 529 deletions
diff --git a/deps/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/lib/ngtcp2_conn.c index 41e5f4d915e..ff8c608b776 100644 --- a/deps/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/lib/ngtcp2_conn.c @@ -359,6 +359,29 @@ static int conn_call_deactivate_dcid(ngtcp2_conn *conn, conn, NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE, dcid); } +static void conn_call_delete_crypto_aead_ctx(ngtcp2_conn *conn, + ngtcp2_crypto_aead_ctx *aead_ctx) { + if (!aead_ctx->native_handle) { + return; + } + + assert(conn->callbacks.delete_crypto_aead_ctx); + + conn->callbacks.delete_crypto_aead_ctx(conn, aead_ctx, conn->user_data); +} + +static void +conn_call_delete_crypto_cipher_ctx(ngtcp2_conn *conn, + ngtcp2_crypto_cipher_ctx *cipher_ctx) { + if (!cipher_ctx->native_handle) { + return; + } + + assert(conn->callbacks.delete_crypto_cipher_ctx); + + conn->callbacks.delete_crypto_cipher_ctx(conn, cipher_ctx, conn->user_data); +} + static int crypto_offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return *(int64_t *)lhs < *(int64_t *)rhs; @@ -458,9 +481,6 @@ static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_frame_chain_list_del(pktns->tx.frq, mem); - ngtcp2_vec_del(pktns->crypto.rx.hp_key, mem); - ngtcp2_vec_del(pktns->crypto.tx.hp_key, mem); - ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem); @@ -513,25 +533,46 @@ static int ts_retired_less(const ngtcp2_pq_entry *lhs, return a->ts_retired < b->ts_retired; } -static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) { +/* + * conn_reset_conn_stat_cc resets congestion state in |cstat|. + */ +static void conn_reset_conn_stat_cc(ngtcp2_conn *conn, + ngtcp2_conn_stat *cstat) { cstat->latest_rtt = 0; cstat->min_rtt = UINT64_MAX; - cstat->smoothed_rtt = NGTCP2_DEFAULT_INITIAL_RTT; - cstat->rttvar = NGTCP2_DEFAULT_INITIAL_RTT / 2; + cstat->smoothed_rtt = conn->local.settings.initial_rtt; + cstat->rttvar = conn->local.settings.initial_rtt / 2; cstat->pto_count = 0; cstat->loss_detection_timer = 0; - // Initializes them with UINT64_MAX. - memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time)); cstat->cwnd = ngtcp2_cc_compute_initcwnd(conn->local.settings.max_udp_payload_size); cstat->ssthresh = UINT64_MAX; cstat->congestion_recovery_start_ts = 0; cstat->bytes_in_flight = 0; - cstat->max_udp_payload_size = conn->local.settings.max_udp_payload_size; cstat->delivery_rate_sec = 0; cstat->recv_rate_sec = 0; } +/* + * reset_conn_stat_recovery resets the fields related to the recovery + * function + */ +static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) { + // Initializes them with UINT64_MAX. + memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time)); + memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts)); +} + +/* + * conn_reset_conn_stat resets |cstat|. The following fields are not + * reset: initial_rtt, max_udp_payload_size, bytes_sent, and + * bytes_recv. + */ +static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) { + conn_reset_conn_stat_cc(conn, cstat); + reset_conn_stat_recovery(cstat); +} + static void conn_reset_rx_rate(ngtcp2_conn *conn) { conn->rx.rate.start_ts = UINT64_MAX; conn->rx.rate.received = 0; @@ -551,9 +592,15 @@ static void conn_update_recv_rate(ngtcp2_conn *conn, size_t datalen, assert(conn->cstat.min_rtt); - window = conn->cstat.min_rtt == UINT64_MAX ? NGTCP2_DEFAULT_INITIAL_RTT + window = conn->cstat.min_rtt == UINT64_MAX ? conn->cstat.initial_rtt : conn->cstat.min_rtt * 2; + /* If settings.initial_rtt is zero for whatever reason then window + can be zero and we can end up with a division by zero error when + bps is set below. If this assert fails, check that + settings.initial_rtt is not zero. */ + assert(window); + if (window > ts - conn->rx.rate.start_ts) { return; } @@ -621,6 +668,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_dcid_retired_init; } + rv = ngtcp2_gaptr_init(&(*pconn)->dcid.seqgap, mem); + if (rv != 0) { + goto fail_seqgap_init; + } + rv = ngtcp2_ksl_init(&(*pconn)->scid.set, cid_less, sizeof(ngtcp2_cid), mem); if (rv != 0) { goto fail_scid_set_init; @@ -677,22 +729,14 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.settings.token.len = 0; } - if (params->active_connection_id_limit == 0) { - (*pconn)->local.settings.transport_params.active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; - } - - (*pconn)->local.settings.transport_params.initial_scid = *scid; - - if (scid->datalen == 0) { - (*pconn)->local.settings.transport_params.preferred_address_present = 0; - } - if (settings->max_udp_payload_size == 0) { (*pconn)->local.settings.max_udp_payload_size = NGTCP2_DEFAULT_MAX_PKTLEN; } conn_reset_conn_stat(*pconn, &(*pconn)->cstat); + (*pconn)->cstat.initial_rtt = settings->initial_rtt; + (*pconn)->cstat.max_udp_payload_size = + (*pconn)->local.settings.max_udp_payload_size; ngtcp2_rst_init(&(*pconn)->rst); @@ -746,10 +790,9 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_scident; } - ngtcp2_scid_init(scident, 0, scid, - params->stateless_reset_token_present - ? params->stateless_reset_token - : NULL); + /* Set stateless reset token later if it is available in the local + transport parameters */ + ngtcp2_scid_init(scident, 0, scid, NULL); rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); if (rv != 0) { @@ -758,52 +801,29 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, scident = NULL; - if (server && params->preferred_address_present) { - scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); - if (scident == NULL) { - rv = NGTCP2_ERR_NOMEM; - goto fail_scident; - } - - ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid, - params->preferred_address.stateless_reset_token); - - rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); - if (rv != 0) { - goto fail_scid_set_insert; - } - - scident = NULL; - - (*pconn)->scid.last_seq = 1; - } - ngtcp2_dcid_init(&(*pconn)->dcid.current, 0, dcid, NULL); ngtcp2_path_copy(&(*pconn)->dcid.current.ps.path, path); + rv = ngtcp2_gaptr_push(&(*pconn)->dcid.seqgap, 0, 1); + if (rv != 0) { + goto fail_seqgap_push; + } + + (*pconn)->server = server; (*pconn)->oscid = *scid; (*pconn)->callbacks = *callbacks; (*pconn)->version = version; (*pconn)->mem = mem; (*pconn)->user_data = user_data; - (*pconn)->rx.unsent_max_offset = (*pconn)->rx.max_offset = - params->initial_max_data; - (*pconn)->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi; - (*pconn)->remote.bidi.max_streams = params->initial_max_streams_bidi; - (*pconn)->remote.uni.unsent_max_streams = params->initial_max_streams_uni; - (*pconn)->remote.uni.max_streams = params->initial_max_streams_uni; (*pconn)->idle_ts = settings->initial_ts; (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX; ngtcp2_qlog_start(&(*pconn)->qlog, server ? &settings->qlog.odcid : dcid, server); - ngtcp2_qlog_parameters_set_transport_params( - &(*pconn)->qlog, &(*pconn)->local.settings.transport_params, - (*pconn)->server, - /* local = */ 1); return 0; +fail_seqgap_push: fail_scid_set_insert: ngtcp2_mem_free(mem, scident); fail_scident: @@ -830,6 +850,8 @@ fail_strms_init: delete_scid(&(*pconn)->scid.set, mem); ngtcp2_ksl_free(&(*pconn)->scid.set); fail_scid_set_init: + ngtcp2_gaptr_free(&(*pconn)->dcid.seqgap); +fail_seqgap_init: ngtcp2_ringbuf_free(&(*pconn)->dcid.retired); fail_dcid_retired_init: ngtcp2_ringbuf_free(&(*pconn)->dcid.unused); @@ -856,6 +878,16 @@ int ngtcp2_conn_client_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.bidi.next_stream_id = 0; (*pconn)->local.uni.next_stream_id = 2; + rv = ngtcp2_conn_commit_local_transport_params(*pconn); + if (rv != 0) { + ngtcp2_conn_del(*pconn); + return rv; + } + + ngtcp2_qlog_parameters_set_transport_params( + &(*pconn)->qlog, &(*pconn)->local.settings.transport_params, + (*pconn)->server, NGTCP2_QLOG_SIDE_LOCAL); + return 0; } @@ -866,24 +898,15 @@ int ngtcp2_conn_server_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, const ngtcp2_settings *settings, const ngtcp2_mem *mem, void *user_data) { int rv; - ngtcp2_transport_params *params; - rv = conn_new(pconn, dcid, scid, path, version, callbacks, settings, mem, user_data, 1); if (rv != 0) { return rv; } - (*pconn)->server = 1; (*pconn)->state = NGTCP2_CS_SERVER_INITIAL; (*pconn)->local.bidi.next_stream_id = 1; (*pconn)->local.uni.next_stream_id = 3; - params = &(*pconn)->local.settings.transport_params; - if (dcid->datalen == 0) { - /* Client uses zero-length Connection ID */ - params->active_connection_id_limit = 0; - } - if ((*pconn)->local.settings.token.len) { /* Usage of token lifts amplification limit */ (*pconn)->flags |= NGTCP2_CONN_FLAG_SADDR_VERIFIED; @@ -930,13 +953,71 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { ngtcp2_qlog_end(&conn->qlog); + if (conn->early.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx); + + if (conn->crypto.key_update.old_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx); + } + if (conn->crypto.key_update.new_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.new_rx_ckm->aead_ctx); + } + if (conn->crypto.key_update.new_tx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.new_tx_ckm->aead_ctx); + } + + if (conn->pktns.crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, + &conn->pktns.crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.rx.hp_ctx); + + if (conn->pktns.crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, + &conn->pktns.crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.tx.hp_ctx); + + if (conn->hs_pktns) { + if (conn->hs_pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->hs_pktns->crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.rx.hp_ctx); + + if (conn->hs_pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->hs_pktns->crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.tx.hp_ctx); + } + if (conn->in_pktns) { + if (conn->in_pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->in_pktns->crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.rx.hp_ctx); + + if (conn->in_pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->in_pktns->crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.tx.hp_ctx); + } + + conn_call_delete_crypto_aead_ctx(conn, &conn->crypto.retry_aead_ctx); + ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base); ngtcp2_mem_free(conn->mem, conn->local.settings.token.base); ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_tx_ckm, conn->mem); - ngtcp2_vec_del(conn->early.hp_key, conn->mem); ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); pktns_free(&conn->pktns, conn->mem); @@ -961,6 +1042,7 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { ngtcp2_pq_free(&conn->scid.used); delete_scid(&conn->scid.set, conn->mem); ngtcp2_ksl_free(&conn->scid.set); + ngtcp2_gaptr_free(&conn->dcid.seqgap); ngtcp2_ringbuf_free(&conn->dcid.retired); ngtcp2_ringbuf_free(&conn->dcid.unused); @@ -1031,18 +1113,20 @@ static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) { * Out of memory. */ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, - ngtcp2_acktr *acktr, uint8_t type, + ngtcp2_pktns *pktns, uint8_t type, ngtcp2_tstamp ts, ngtcp2_duration ack_delay, uint64_t ack_delay_exponent) { - /* TODO Measure an actual size of ACK bloks to find the best default - value. */ + /* TODO Measure an actual size of ACK blocks to find the best + default value. */ const size_t initial_max_ack_blks = 8; int64_t last_pkt_num; + ngtcp2_acktr *acktr = &pktns->acktr; ngtcp2_ack_blk *blk; ngtcp2_ksl_it it; ngtcp2_acktr_entry *rpkt; ngtcp2_ack *ack; size_t blk_idx; + ngtcp2_tstamp largest_ack_ts; int rv; if (acktr->flags & NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK) { @@ -1071,22 +1155,35 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, ack = &conn->tx.ack->ack; - rpkt = ngtcp2_ksl_it_get(&it); - last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); ack->type = NGTCP2_FRAME_ACK; - ack->largest_ack = rpkt->pkt_num; - ack->first_ack_blklen = rpkt->len - 1; + ack->num_blks = 0; + + rpkt = ngtcp2_ksl_it_get(&it); + + if (rpkt->pkt_num == pktns->rx.max_pkt_num) { + last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); + largest_ack_ts = rpkt->tstamp; + ack->largest_ack = rpkt->pkt_num; + ack->first_ack_blklen = rpkt->len - 1; + + ngtcp2_ksl_it_next(&it); + } else { + assert(rpkt->pkt_num < pktns->rx.max_pkt_num); + + last_pkt_num = pktns->rx.max_pkt_num; + largest_ack_ts = pktns->rx.max_pkt_ts; + ack->largest_ack = pktns->rx.max_pkt_num; + ack->first_ack_blklen = 0; + } + if (type == NGTCP2_PKT_SHORT) { - ack->ack_delay_unscaled = ts - rpkt->tstamp; + ack->ack_delay_unscaled = ts - largest_ack_ts; ack->ack_delay = ack->ack_delay_unscaled / NGTCP2_MICROSECONDS / (1UL << ack_delay_exponent); } else { ack->ack_delay_unscaled = 0; ack->ack_delay = 0; } - ack->num_blks = 0; - - ngtcp2_ksl_it_next(&it); for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { if (ack->num_blks == NGTCP2_MAX_ACK_BLKS) { @@ -1189,11 +1286,10 @@ static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_rtb *rtb, if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) { conn->cstat.last_tx_pkt_ts[rtb->pktns_id] = ent->ts; - /* I think pseudo code is wrong; timer should be set when - ack-eliciting packet is sent. */ - ngtcp2_conn_set_loss_detection_timer(conn, ent->ts); } + ngtcp2_conn_set_loss_detection_timer(conn, ent->ts); + return 0; } @@ -1264,19 +1360,52 @@ static size_t conn_retry_early_payloadlen(ngtcp2_conn *conn) { return 0; } +static void conn_cryptofrq_clear(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { + ngtcp2_frame_chain *frc; + ngtcp2_ksl_it it; + + for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); + ngtcp2_ksl_it_next(&it)) { + frc = ngtcp2_ksl_it_get(&it); + ngtcp2_frame_chain_del(frc, conn->mem); + } + ngtcp2_ksl_clear(&pktns->crypto.tx.frq); +} + /* - * conn_cryptofrq_top returns the element which sits on top of the - * queue. The queue must not be empty. + * conn_cryptofrq_unacked_offset returns the CRYPTO frame offset by + * taking into account acknowledged offset. If there is no data to + * send, this function returns (uint64_t)-1. */ -static ngtcp2_frame_chain *conn_cryptofrq_top(ngtcp2_conn *conn, +static uint64_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { + ngtcp2_frame_chain *frc; + ngtcp2_crypto *fr; + ngtcp2_range gap; + ngtcp2_rtb *rtb = &pktns->rtb; ngtcp2_ksl_it it; + size_t datalen; + (void)conn; - assert(ngtcp2_ksl_len(&pktns->crypto.tx.frq)); + for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); + ngtcp2_ksl_it_next(&it)) { + frc = ngtcp2_ksl_it_get(&it); + fr = &frc->fr.crypto; + + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset); + + datalen = ngtcp2_vec_len(fr->data, fr->datacnt); + + if (gap.begin <= fr->offset) { + return fr->offset; + } + if (gap.begin < fr->offset + datalen) { + return gap.begin; + } + } - it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); - return ngtcp2_ksl_it_get(&it); + return (uint64_t)-1; } static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, @@ -1286,7 +1415,6 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, uint64_t offset, end_offset; size_t idx, end_idx; uint64_t base_offset, end_base_offset; - ngtcp2_ksl_it gapit; ngtcp2_range gap; ngtcp2_rtb *rtb = &pktns->rtb; ngtcp2_vec *v; @@ -1305,9 +1433,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, offset = fr->offset; base_offset = 0; - gapit = - ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, offset); - gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit); + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, offset); if (gap.begin < offset) { gap.begin = offset; } @@ -1370,6 +1496,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, } nfr = &nfrc->fr.crypto; + nfr->type = NGTCP2_FRAME_CRYPTO; memcpy(nfr->data, fr->data + end_idx, sizeof(nfr->data[0]) * (fr->datacnt - end_idx)); @@ -1707,6 +1834,8 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, int pkt_empty = 1; int padded = 0; int hd_logged = 0; + uint64_t crypto_offset; + ngtcp2_ssize num_reclaimed; switch (type) { case NGTCP2_PKT_INITIAL: @@ -1731,7 +1860,7 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, cc.aead = pktns->crypto.ctx.aead; cc.hp = pktns->crypto.ctx.hp; cc.ckm = pktns->crypto.tx.ckm; - cc.hp_key = pktns->crypto.tx.hp_key; + cc.hp_ctx = pktns->crypto.tx.hp_ctx; cc.encrypt = conn->callbacks.encrypt; cc.hp_mask = conn->callbacks.hp_mask; @@ -1757,7 +1886,7 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, return 0; } - rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, type, ts, + rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, /* ack_delay = */ 0, NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); if (rv != 0) { @@ -1776,11 +1905,17 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, } } +build_pkt: for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { left = ngtcp2_ppe_left(&ppe); - left = ngtcp2_pkt_crypto_max_datalen( - conn_cryptofrq_top(conn, pktns)->fr.crypto.offset, left, left); + crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); + if (crypto_offset == (size_t)-1) { + conn_cryptofrq_clear(conn, pktns); + break; + } + + left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left); if (left == (size_t)-1) { break; } @@ -1806,7 +1941,33 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, pkt_empty = 0; rtb_entry_flags |= - NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_CRYPTO_PKT; + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; + } + + if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) && + pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) { + num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, + pktns->rtb.probe_pkt_left + 1); + if (num_reclaimed < 0) { + ngtcp2_frame_chain_list_del(frq, conn->mem); + return rv; + } + if (num_reclaimed) { + goto build_pkt; + } + /* We had pktns->rtb.num_retransmittable > 0 but the contents of + those packets have been acknowledged (i.e., retransmission in + another packet). For server, in this case, we don't have to + send any probe packet. Client needs to send probe packets + until it knows that server has completed address validation or + handshake has been confirmed. */ + if (pktns->rtb.num_retransmittable == 0 && + (conn->server || + (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | + NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { + pktns->rtb.probe_pkt_left = 0; + ngtcp2_conn_set_loss_detection_timer(conn, ts); + } } /* Don't send any PING frame if client Initial has not been @@ -1961,7 +2122,7 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, uint8_t *dest, } ackfr = NULL; - rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, type, ts, ack_delay, + rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay, ack_delay_exponent); if (rv != 0) { return rv; @@ -1990,6 +2151,11 @@ static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns, conn->cstat.last_tx_pkt_ts[pktns->rtb.pktns_id] = UINT64_MAX; conn->cstat.loss_time[pktns->rtb.pktns_id] = UINT64_MAX; + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx); + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx); + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx); + pktns_del(pktns, conn->mem); *ppktns = NULL; @@ -2386,9 +2552,9 @@ typedef enum { /* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING indicates that packet should be padded */ NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING = 0x01, - /* NGTCP2_WRITE_PKT_FLAG_STREAM_MORE indicates that more stream DATA - may come and it should be encoded into the current packet. */ - NGTCP2_WRITE_PKT_FLAG_STREAM_MORE = 0x02, + /* NGTCP2_WRITE_PKT_FLAG_MORE indicates that more frames might come + and it should be encoded into the current packet. */ + NGTCP2_WRITE_PKT_FLAG_MORE = 0x02, } ngtcp2_write_pkt_flag; /* @@ -2397,13 +2563,14 @@ typedef enum { * packet. It can be NGTCP2_PKT_SHORT or NGTCP2_PKT_0RTT. * * This function can send new stream data. In order to send stream - * data, specify the underlying stream to |data_strm|. If |fin| is - * set to nonzero, it signals that the given data is the final portion - * of the stream. |datav| vector of length |datavcnt| specify stream - * data to send. If no stream data to send, set |strm| to NULL. The - * number of bytes sent to the stream is assigned to |*pdatalen|. If - * 0 length STREAM data is sent, 0 is assigned to |*pdatalen|. The - * caller should initialize |*pdatalen| to -1. + * data, specify the underlying stream and parameters to + * |vmsg|->stream. If |vmsg|->stream.fin is set to nonzero, it + * signals that the given data is the final portion of the stream. + * |vmsg|->stream.data vector of length |vmsg|->stream.datacnt + * specifies stream data to send. The number of bytes sent to the + * stream is assigned to *|vmsg|->stream.pdatalen. If 0 length STREAM + * data is sent, 0 is assigned to it. The caller should initialize + * *|vmsg|->stream.pdatalen to -1. * * If |require_padding| is nonzero, padding bytes are added to occupy * the remaining packet payload. @@ -2419,10 +2586,8 @@ typedef enum { * Stream data could not be written because of flow control. */ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, ngtcp2_ssize *pdatalen, - uint8_t type, ngtcp2_strm *data_strm, - int fin, const ngtcp2_vec *datav, - size_t datavcnt, uint8_t flags, + size_t destlen, ngtcp2_vmsg *vmsg, + uint8_t type, uint8_t flags, ngtcp2_tstamp ts) { int rv = 0; ngtcp2_crypto_cc *cc = &conn->pkt.cc; @@ -2439,7 +2604,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, int stream_blocked = 0; ngtcp2_pktns *pktns = &conn->pktns; size_t left; - size_t datalen = ngtcp2_vec_len(datav, datavcnt); + size_t datalen = 0; ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT]; size_t datacnt; uint8_t rtb_entry_flags = NGTCP2_RTB_FLAG_NONE; @@ -2447,12 +2612,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_path_challenge_entry *pcent; uint8_t hd_flags; int require_padding = (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) != 0; - int stream_more = (flags & NGTCP2_WRITE_PKT_FLAG_STREAM_MORE) != 0; + int write_more = (flags & NGTCP2_WRITE_PKT_FLAG_MORE) != 0; int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; size_t min_pktlen = conn_min_short_pktlen(conn); int padded = 0; int credit_expanded = 0; ngtcp2_cc_pkt cc_pkt; + uint64_t crypto_offset; + uint64_t stream_offset; + ngtcp2_ssize num_reclaimed; + int fin; /* Return 0 if destlen is less than minimum packet length which can trigger Stateless Reset */ @@ -2460,13 +2629,20 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, return 0; } - if (data_strm) { - ndatalen = conn_enforce_flow_control(conn, data_strm, datalen); - /* 0 length STREAM frame is allowed */ - if (ndatalen || datalen == 0) { - send_stream = 1; - } else { - stream_blocked = 1; + if (vmsg) { + switch (vmsg->type) { + case NGTCP2_VMSG_TYPE_STREAM: + datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); + ndatalen = conn_enforce_flow_control(conn, vmsg->stream.strm, datalen); + /* 0 length STREAM frame is allowed */ + if (ndatalen || datalen == 0) { + send_stream = 1; + } else { + stream_blocked = 1; + } + break; + default: + break; } } @@ -2478,7 +2654,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, ? NGTCP2_PKT_FLAG_KEY_PHASE : NGTCP2_PKT_FLAG_NONE; cc->ckm = pktns->crypto.tx.ckm; - cc->hp_key = pktns->crypto.tx.hp_key; + cc->hp_ctx = pktns->crypto.tx.hp_ctx; /* transport parameter is only valid after handshake completion which means we don't know how many connection ID that remote @@ -2499,7 +2675,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } hd_flags = NGTCP2_PKT_FLAG_LONG_FORM; cc->ckm = conn->early.ckm; - cc->hp_key = conn->early.hp_key; + cc->hp_ctx = conn->early.hp_ctx; break; default: /* Unreachable */ @@ -2566,7 +2742,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } rv = conn_create_ack_frame( - conn, &ackfr, &pktns->acktr, type, ts, conn_compute_ack_delay(conn), + conn, &ackfr, pktns, type, ts, conn_compute_ack_delay(conn), conn->local.settings.transport_params.ack_delay_exponent); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); @@ -2585,7 +2761,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } } + build_pkt: for (pfrc = &pktns->tx.frq; *pfrc;) { + if ((*pfrc)->binder && + ((*pfrc)->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK)) { + frc = *pfrc; + *pfrc = (*pfrc)->next; + ngtcp2_frame_chain_del(frc, conn->mem); + continue; + } + switch ((*pfrc)->fr.type) { case NGTCP2_FRAME_STOP_SENDING: strm = @@ -2649,7 +2834,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; } @@ -2657,8 +2843,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { left = ngtcp2_ppe_left(ppe); - left = ngtcp2_pkt_crypto_max_datalen( - conn_cryptofrq_top(conn, pktns)->fr.crypto.offset, left, left); + crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); + if (crypto_offset == (size_t)-1) { + conn_cryptofrq_clear(conn, pktns); + break; + } + + left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left); if (left == (size_t)-1) { break; @@ -2683,7 +2874,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, pfrc = &(*pfrc)->next; pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; } } @@ -2714,7 +2906,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, assert(NGTCP2_ERR_NOBUF == rv); } else { pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; } } @@ -2745,7 +2938,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, assert(NGTCP2_ERR_NOBUF == rv); } else { pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; } } @@ -2776,7 +2970,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, pkt_empty = 0; credit_expanded = 1; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; strm->rx.max_offset = strm->rx.unsent_max_offset; } @@ -2786,11 +2981,17 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, continue; } + stream_offset = ngtcp2_strm_streamfrq_unacked_offset(strm); + if (stream_offset == (uint64_t)-1) { + ngtcp2_strm_streamfrq_clear(strm); + ngtcp2_conn_tx_strmq_pop(conn); + continue; + } + left = ngtcp2_ppe_left(ppe); - left = ngtcp2_pkt_stream_max_datalen( - strm->stream_id, ngtcp2_strm_streamfrq_top(strm)->fr.stream.offset, - left, left); + left = ngtcp2_pkt_stream_max_datalen(strm->stream_id, stream_offset, + left, left); if (left == (size_t)-1) { break; @@ -2816,7 +3017,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, pfrc = &(*pfrc)->next; pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; if (ngtcp2_strm_streamfrq_empty(strm)) { ngtcp2_conn_tx_strmq_pop(conn); @@ -2837,7 +3039,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, decrease packet count. */ if (ackfr == NULL && credit_expanded) { rv = conn_create_ack_frame( - conn, &ackfr, &pktns->acktr, type, ts, /* ack_delay = */ 0, + conn, &ackfr, pktns, type, ts, /* ack_delay = */ 0, conn->local.settings.transport_params.ack_delay_exponent); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); @@ -2855,6 +3057,29 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } } } + + if (rv != NGTCP2_ERR_NOBUF && !send_stream && + !(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) && + pktns->rtb.num_retransmittable && pktns->tx.frq == NULL && + pktns->rtb.probe_pkt_left) { + num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, + pktns->rtb.probe_pkt_left + 1); + if (num_reclaimed < 0) { + return rv; + } + if (num_reclaimed) { + goto build_pkt; + } + + /* We had pktns->rtb.num_retransmittable > 0 but the contents of + those packets have been acknowledged (i.e., retransmission in + another packet). In this case, we don't have to send any + probe packet. */ + if (pktns->rtb.num_retransmittable == 0) { + pktns->rtb.probe_pkt_left = 0; + ngtcp2_conn_set_loss_detection_timer(conn, ts); + } + } } else { pfrc = conn->pkt.pfrc; rtb_entry_flags |= conn->pkt.rtb_entry_flags; @@ -2865,12 +3090,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, left = ngtcp2_ppe_left(ppe); if (rv != NGTCP2_ERR_NOBUF && send_stream && *pfrc == NULL && - (ndatalen = ngtcp2_pkt_stream_max_datalen(data_strm->stream_id, - data_strm->tx.offset, ndatalen, - left)) != (size_t)-1 && + (ndatalen = ngtcp2_pkt_stream_max_datalen( + vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen, + left)) != (size_t)-1 && (ndatalen || datalen == 0)) { datacnt = ngtcp2_vec_copy_at_most( - data, &ndatalen, NGTCP2_MAX_STREAM_DATACNT, datav, datavcnt, ndatalen); + data, &ndatalen, NGTCP2_MAX_STREAM_DATACNT, vmsg->stream.data, + vmsg->stream.datacnt, ndatalen); rv = ngtcp2_frame_chain_stream_datacnt_new(&nfrc, datacnt, conn->mem); if (rv != 0) { @@ -2880,12 +3106,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, nfrc->fr.stream.type = NGTCP2_FRAME_STREAM; nfrc->fr.stream.flags = 0; - nfrc->fr.stream.stream_id = data_strm->stream_id; - nfrc->fr.stream.offset = data_strm->tx.offset; + nfrc->fr.stream.stream_id = vmsg->stream.strm->stream_id; + nfrc->fr.stream.offset = vmsg->stream.strm->tx.offset; nfrc->fr.stream.datacnt = datacnt; ngtcp2_vec_copy(nfrc->fr.stream.data, data, datacnt); - fin = fin && ndatalen == datalen; + fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) && + ndatalen == datalen; nfrc->fr.stream.fin = (uint8_t)fin; rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); @@ -2897,17 +3124,18 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, pfrc = &(*pfrc)->next; pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + rtb_entry_flags |= + NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE; - data_strm->tx.offset += ndatalen; + vmsg->stream.strm->tx.offset += ndatalen; conn->tx.offset += ndatalen; if (fin) { - ngtcp2_strm_shutdown(data_strm, NGTCP2_STRM_FLAG_SHUT_WR); + ngtcp2_strm_shutdown(vmsg->stream.strm, NGTCP2_STRM_FLAG_SHUT_WR); } - if (pdatalen) { - *pdatalen = (ngtcp2_ssize)ndatalen; + if (vmsg->stream.pdatalen) { + *vmsg->stream.pdatalen = (ngtcp2_ssize)ndatalen; } } else { send_stream = 0; @@ -2922,7 +3150,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, if (conn->pktns.rtb.probe_pkt_left == 0) { return 0; } - } else if (stream_more) { + } else if (write_more) { conn->pkt.pfrc = pfrc; conn->pkt.pkt_empty = pkt_empty; conn->pkt.rtb_entry_flags = rtb_entry_flags; @@ -2930,7 +3158,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING; if (send_stream) { - return NGTCP2_ERR_WRITE_STREAM_MORE; + return NGTCP2_ERR_WRITE_MORE; } if (ngtcp2_conn_get_max_data_left(conn) && stream_blocked) { @@ -2939,8 +3167,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) { - if (pktns->rtb.probe_pkt_left || - pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT) { + if (pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT) { lfr.type = NGTCP2_FRAME_PING; rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr); @@ -2950,9 +3177,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, packet is still empty. */ } else { rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; - if (pktns->rtb.probe_pkt_left) { - rtb_entry_flags |= NGTCP2_RTB_FLAG_PROBE; - } pktns->tx.num_non_ack_pkt = 0; } } else { @@ -2966,6 +3190,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, before ngtcp2_rtb_entry is safely created and added. */ lfr.type = NGTCP2_FRAME_PADDING; if ((require_padding || + /* Making full sized packet will help GSO a bit */ + ngtcp2_ppe_left(ppe) < 10 || (type == NGTCP2_PKT_0RTT && conn->state == NGTCP2_CS_CLIENT_INITIAL)) && ngtcp2_ppe_left(ppe)) { lfr.padding.len = ngtcp2_ppe_padding(ppe); @@ -2989,6 +3215,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_qlog_pkt_sent_end(&conn->qlog, hd, (size_t)nwrite); + /* TODO ack-eliciting vs needs-tracking */ + /* probe packet needs tracking but it does not need ACK, could be lost. */ if ((rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) || padded) { rv = ngtcp2_rtb_entry_new(&ent, hd, NULL, ts, (size_t)nwrite, rtb_entry_flags, conn->mem); @@ -3090,7 +3318,7 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, cc.aead = pktns->crypto.ctx.aead; cc.hp = pktns->crypto.ctx.hp; cc.ckm = pktns->crypto.tx.ckm; - cc.hp_key = pktns->crypto.tx.hp_key; + cc.hp_ctx = pktns->crypto.tx.hp_ctx; cc.encrypt = conn->callbacks.encrypt; cc.hp_mask = conn->callbacks.hp_mask; @@ -3206,9 +3434,9 @@ static int conn_handshake_remnants_left(ngtcp2_conn *conn) { ngtcp2_pktns *hs_pktns = conn->hs_pktns; return !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || - (in_pktns && (in_pktns->rtb.num_ack_eliciting || + (in_pktns && (in_pktns->rtb.num_retransmittable || ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) || - (hs_pktns && (hs_pktns->rtb.num_ack_eliciting || + (hs_pktns && (hs_pktns->rtb.num_retransmittable || ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq))); } @@ -3388,9 +3616,9 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, } assert(conn->callbacks.rand); - rv = conn->callbacks.rand(conn, lfr.path_challenge.data, + rv = conn->callbacks.rand(lfr.path_challenge.data, sizeof(lfr.path_challenge.data), - NGTCP2_RAND_CTX_PATH_CHALLENGE, conn->user_data); + NGTCP2_RAND_CTX_PATH_CHALLENGE); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -3399,7 +3627,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, /* TODO reconsider this. This might get larger pretty quickly than validation timeout which is just around 3*PTO. */ - expiry = ts + 6ULL * NGTCP2_DEFAULT_INITIAL_RTT * (1ULL << pv->loss_count); + expiry = ts + 6ULL * conn->cstat.initial_rtt * (1ULL << pv->loss_count); ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry); @@ -3505,17 +3733,18 @@ static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { return strm->cycle; } -/* - * conn_resched_frames reschedules frames linked from |*pfrc| for - * retransmission. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, +uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { + ngtcp2_strm *strm; + + if (ngtcp2_pq_empty(&conn->tx.strmq)) { + return 0; + } + + strm = ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe); + return strm->cycle; +} + +int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_frame_chain **pfrc) { ngtcp2_frame_chain **first = pfrc; ngtcp2_frame_chain *frc; @@ -3605,7 +3834,6 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_rtb *rtb = &conn->pktns.rtb; ngtcp2_rtb *in_rtb; uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1]; - ngtcp2_frame_chain *frc = NULL; ngtcp2_vec *token; if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { @@ -3622,7 +3850,8 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, retry.odcid = conn->dcid.current.cid; rv = ngtcp2_pkt_verify_retry_tag(&retry, pkt, pktlen, conn->callbacks.encrypt, - &conn->crypto.retry_aead); + &conn->crypto.retry_aead, + &conn->crypto.retry_aead_ctx); if (rv != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "unable to verify Retry packet integrity"); @@ -3659,22 +3888,13 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, /* Just freeing memory is dangerous because we might free twice. */ - ngtcp2_rtb_remove_all(rtb, &frc, &conn->cstat); - - rv = conn_resched_frames(conn, &conn->pktns, &frc); + rv = ngtcp2_rtb_remove_all(rtb, conn, &conn->pktns, &conn->cstat); if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } - frc = NULL; - ngtcp2_rtb_remove_all(in_rtb, &frc, &conn->cstat); - - rv = conn_resched_frames(conn, in_pktns, &frc); + rv = ngtcp2_rtb_remove_all(in_rtb, conn, in_pktns, &conn->cstat); if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } @@ -3692,6 +3912,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_cpymem(token->base, retry.token.base, retry.token.len); + reset_conn_stat_recovery(&conn->cstat); conn_reset_congestion_state(conn); return 0; @@ -3699,15 +3920,11 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_frame_chain *frc = NULL; int rv; ngtcp2_duration pto = conn_compute_pto(conn, pktns); - ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &frc, cstat, pto, ts); - - rv = conn_resched_frames(conn, pktns, &frc); + rv = ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, conn, pktns, cstat, pto, ts); if (rv != 0) { - ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } @@ -3983,7 +4200,7 @@ static ngtcp2_ssize decrypt_pkt(uint8_t *dest, const ngtcp2_crypto_aead *aead, ngtcp2_crypto_create_nonce(nonce, ckm->iv.base, ckm->iv.len, pkt_num); - rv = decrypt(dest, aead, payload, payloadlen, ckm->key.base, nonce, + rv = decrypt(dest, aead, &ckm->aead_ctx, payload, payloadlen, nonce, ckm->iv.len, ad, adlen); if (rv != 0) { @@ -4017,7 +4234,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen, const ngtcp2_crypto_cipher *hp, const uint8_t *pkt, size_t pktlen, size_t pkt_num_offset, ngtcp2_crypto_km *ckm, - const ngtcp2_vec *hp_key, + const ngtcp2_crypto_cipher_ctx *hp_ctx, ngtcp2_hp_mask hp_mask) { size_t sample_offset; uint8_t *p = dest; @@ -4037,7 +4254,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen, sample_offset = pkt_num_offset + 4; - rv = hp_mask(mask, hp, hp_key->base, pkt + sample_offset); + rv = hp_mask(mask, hp, hp_ctx, pkt + sample_offset); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -4083,8 +4300,12 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, int rv; uint64_t offset; + if (!strm->rx.rob) { + return 0; + } + for (;;) { - datalen = ngtcp2_rob_data_at(&strm->rx.rob, &data, rx_offset); + datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset); if (datalen == 0) { assert(rx_offset == ngtcp2_strm_rx_offset(strm)); return 0; @@ -4098,7 +4319,7 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, return rv; } - ngtcp2_rob_pop(&strm->rx.rob, rx_offset - datalen, datalen); + ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen); } } @@ -4129,7 +4350,7 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, * conn_reset_congestion_state resets congestion state. */ static void conn_reset_congestion_state(ngtcp2_conn *conn) { - conn_reset_conn_stat(conn, &conn->cstat); + conn_reset_conn_stat_cc(conn, &conn->cstat); conn_reset_rx_rate(conn); @@ -4210,16 +4431,16 @@ static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) { * pktns_commit_recv_pkt_num marks packet number |pkt_num| as * received. */ -static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num) { +static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, + ngtcp2_tstamp ts) { int rv; - ngtcp2_ksl_it it; - ngtcp2_range range; if (pktns->rx.max_pkt_num + 1 != pkt_num) { ngtcp2_acktr_immediate_ack(&pktns->acktr); } if (pktns->rx.max_pkt_num < pkt_num) { pktns->rx.max_pkt_num = pkt_num; + pktns->rx.max_pkt_ts = ts; } rv = ngtcp2_gaptr_push(&pktns->rx.pngap, (uint64_t)pkt_num, 1); @@ -4228,9 +4449,7 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num) { } if (ngtcp2_ksl_len(&pktns->rx.pngap.gap) > 256) { - it = ngtcp2_ksl_begin(&pktns->rx.pngap.gap); - range = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it); - ngtcp2_ksl_remove(&pktns->rx.pngap.gap, NULL, &range); + ngtcp2_gaptr_drop_first_gap(&pktns->rx.pngap); } return 0; @@ -4310,7 +4529,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, ngtcp2_crypto_aead *aead; ngtcp2_crypto_cipher *hp; ngtcp2_crypto_km *ckm; - const ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx *hp_ctx; ngtcp2_hp_mask hp_mask; ngtcp2_decrypt decrypt; size_t aead_overhead; @@ -4539,14 +4758,14 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, aead = &pktns->crypto.ctx.aead; hp = &pktns->crypto.ctx.hp; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; assert(ckm); assert(hp_mask); assert(decrypt); nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen, - (size_t)nread, ckm, hp_key, hp_mask); + (size_t)nread, ckm, hp_ctx, hp_mask); if (nwrite < 0) { if (ngtcp2_err_is_fatal((int)nwrite)) { return nwrite; @@ -4712,7 +4931,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen); - rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num); + rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, pkt_ts); if (rv != 0) { return rv; } @@ -4886,6 +5105,10 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, uint32_t sdflags; int handshake_completed = conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; + if (!strm->rx.rob) { + return 0; + } + for (;;) { /* Stop calling callback if application has called ngtcp2_conn_shutdown_stream_read() inside the callback. @@ -4894,7 +5117,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, return 0; } - datalen = ngtcp2_rob_data_at(&strm->rx.rob, &data, rx_offset); + datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset); if (datalen == 0) { assert(rx_offset == ngtcp2_strm_rx_offset(strm)); return 0; @@ -4917,12 +5140,10 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, return rv; } - ngtcp2_rob_pop(&strm->rx.rob, rx_offset - datalen, datalen); + ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen); } } -static int conn_on_crypto_timeout(ngtcp2_conn *conn, ngtcp2_pktns *pktns); - /* * conn_recv_crypto is called when CRYPTO frame |fr| is received. * |rx_offset_base| is the offset in the entire TLS handshake stream. @@ -4975,16 +5196,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, send a packet containing unacknowledged CRYPTO data earlier than the PTO expiry, subject to address validation limits; ... */ - rv = conn_on_crypto_timeout(conn, conn->in_pktns); - if (rv != 0) { - return rv; - } conn->in_pktns->rtb.probe_pkt_left = 1; - - rv = conn_on_crypto_timeout(conn, conn->hs_pktns); - if (rv != 0) { - return rv; - } conn->hs_pktns->rtb.probe_pkt_left = 1; } return 0; @@ -5004,7 +5216,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, uint64_t offset = rx_offset; rx_offset += datalen; - rv = ngtcp2_rob_remove_prefix(&crypto->rx.rob, rx_offset); + rv = ngtcp2_strm_update_rx_offset(crypto, rx_offset); if (rv != 0) { return rv; } @@ -5216,7 +5428,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, datalen -= ncut; rx_offset += datalen; - rv = ngtcp2_rob_remove_prefix(&strm->rx.rob, rx_offset); + rv = ngtcp2_strm_update_rx_offset(strm, rx_offset); if (rv != 0) { return rv; } @@ -5803,39 +6015,53 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn, return 0; } - if (!found) { - len = ngtcp2_ringbuf_len(&conn->dcid.unused); + if (found) { + return 0; + } + + if (ngtcp2_gaptr_is_pushed(&conn->dcid.seqgap, fr->seq, 1)) { + return 0; + } + + rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, fr->seq, 1); + if (rv != 0) { + return rv; + } + + if (ngtcp2_ksl_len(&conn->dcid.seqgap.gap) > 32) { + ngtcp2_gaptr_drop_first_gap(&conn->dcid.seqgap); + } + + len = ngtcp2_ringbuf_len(&conn->dcid.unused); - if (conn->dcid.current.seq >= conn->dcid.retire_prior_to) { + if (conn->dcid.current.seq >= conn->dcid.retire_prior_to) { + ++extra_dcid; + } + if (pv) { + if (pv->dcid.seq != conn->dcid.current.seq && + pv->dcid.seq >= conn->dcid.retire_prior_to) { ++extra_dcid; } - if (pv) { - if (pv->dcid.seq != conn->dcid.current.seq && - pv->dcid.seq >= conn->dcid.retire_prior_to) { - ++extra_dcid; - } - if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) && - pv->fallback_dcid.seq != conn->dcid.current.seq && - pv->fallback_dcid.seq >= conn->dcid.retire_prior_to) { - ++extra_dcid; - } - } - - if (conn->local.settings.transport_params.active_connection_id_limit <= - len + extra_dcid) { - return NGTCP2_ERR_CONNECTION_ID_LIMIT; + if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) && + pv->fallback_dcid.seq != conn->dcid.current.seq && + pv->fallback_dcid.seq >= conn->dcid.retire_prior_to) { + ++extra_dcid; } + } - if (len >= NGTCP2_MAX_DCID_POOL_SIZE) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, - "too many connection ID"); - return 0; - } + if (conn->local.settings.transport_params.active_connection_id_limit <= + len + extra_dcid) { + return NGTCP2_ERR_CONNECTION_ID_LIMIT; + } - dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused); - ngtcp2_dcid_init(dcid, fr->seq, &fr->cid, fr->stateless_reset_token); + if (len >= NGTCP2_MAX_DCID_POOL_SIZE) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "too many connection ID"); + return 0; } + dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused); + ngtcp2_dcid_init(dcid, fr->seq, &fr->cid, fr->stateless_reset_token); + return 0; } @@ -6042,14 +6268,14 @@ static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) { * User-defined callback function failed. */ static int conn_select_preferred_addr(ngtcp2_conn *conn) { - uint8_t buf[128]; + struct sockaddr_storage buf; ngtcp2_addr addr; int rv; ngtcp2_duration timeout; ngtcp2_pv *pv; ngtcp2_dcid *dcid; - ngtcp2_addr_init(&addr, buf, 0, NULL); + ngtcp2_addr_init(&addr, (struct sockaddr *)&buf, 0, NULL); if (ngtcp2_ringbuf_len(&conn->dcid.unused) == 0) { return 0; @@ -6069,8 +6295,7 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { dcid = ngtcp2_ringbuf_get(&conn->dcid.unused, 0); timeout = 3 * conn_compute_pto(conn, &conn->pktns); - timeout = - ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT)); + timeout = ngtcp2_max(timeout, 6 * conn->cstat.initial_rtt); rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); @@ -6116,8 +6341,17 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED | NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; + conn->pktns.rtb.persistent_congestion_start_ts = ts; + conn_discard_handshake_state(conn, ts); + if (conn->remote.transport_params.preferred_address_present) { + rv = conn_select_preferred_addr(conn); + if (rv != 0) { + return rv; + } + } + if (conn->callbacks.handshake_confirmed) { rv = conn->callbacks.handshake_confirmed(conn, conn->user_data); if (rv != 0) { @@ -6154,7 +6388,8 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_crypto_km *rx_ckm = pktns->crypto.rx.ckm; ngtcp2_crypto_km *tx_ckm = pktns->crypto.tx.ckm; ngtcp2_crypto_km *new_rx_ckm, *new_tx_ckm; - size_t secretlen, keylen, ivlen; + ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}, tx_aead_ctx = {0}; + size_t secretlen, ivlen; if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && (tx_ckm->use_count >= pktns->crypto.ctx.max_encryption || @@ -6175,17 +6410,16 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } secretlen = rx_ckm->secret.len; - keylen = rx_ckm->key.len; ivlen = rx_ckm->iv.len; rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_rx_ckm, - secretlen, keylen, ivlen, conn->mem); + secretlen, ivlen, conn->mem); if (rv != 0) { return rv; } rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_tx_ckm, - secretlen, keylen, ivlen, conn->mem); + secretlen, ivlen, conn->mem); if (rv != 0) { return rv; } @@ -6196,21 +6430,27 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { assert(conn->callbacks.update_key); rv = conn->callbacks.update_key( - conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, - new_rx_ckm->key.base, new_rx_ckm->iv.base, new_tx_ckm->key.base, - new_tx_ckm->iv.base, rx_ckm->secret.base, tx_ckm->secret.base, secretlen, - conn->user_data); + conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, &rx_aead_ctx, + new_rx_ckm->iv.base, &tx_aead_ctx, new_tx_ckm->iv.base, + rx_ckm->secret.base, tx_ckm->secret.base, secretlen, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } + new_rx_ckm->aead_ctx = rx_aead_ctx; + new_tx_ckm->aead_ctx = tx_aead_ctx; + if (!(rx_ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE)) { new_rx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE; new_tx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE; } - ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); - conn->crypto.key_update.old_rx_ckm = NULL; + if (conn->crypto.key_update.old_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx); + ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); + conn->crypto.key_update.old_rx_ckm = NULL; + } return 0; } @@ -6233,7 +6473,11 @@ static void conn_rotate_keys(ngtcp2_conn *conn, int64_t pkt_num) { conn->crypto.key_update.new_rx_ckm = NULL; pktns->crypto.rx.ckm->pkt_num = pkt_num; + assert(pktns->crypto.tx.ckm); + + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); + pktns->crypto.tx.ckm = conn->crypto.key_update.new_tx_ckm; conn->crypto.key_update.new_tx_ckm = NULL; pktns->crypto.tx.ckm->pkt_num = pktns->tx.last_pkt_num + 1; @@ -6318,8 +6562,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, "non-probing packet was received from new remote address"); timeout = 3 * conn_compute_pto(conn, &conn->pktns); - timeout = - ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT)); + timeout = ngtcp2_max(timeout, 6 * conn->cstat.initial_rtt); if (require_new_cid) { dcid = *(ngtcp2_dcid *)ngtcp2_ringbuf_get(&conn->dcid.unused, 0); @@ -6457,7 +6700,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen); - rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num); + rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num, pkt_ts); if (rv != 0) { return rv; } @@ -6466,7 +6709,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_acktr_immediate_ack(&pktns->acktr); } - rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack, ts); + rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack, + pkt_ts); if (rv != 0) { return rv; } @@ -6529,7 +6773,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_crypto_aead *aead; ngtcp2_crypto_cipher *hp; ngtcp2_crypto_km *ckm; - const ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx *hp_ctx; uint8_t plain_hdpkt[1500]; ngtcp2_hp_mask hp_mask; ngtcp2_decrypt decrypt; @@ -6578,7 +6822,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->hs_pktns; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6590,7 +6834,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = &conn->pktns; ckm = conn->early.ckm; - hp_key = conn->early.hp_key; + hp_ctx = &conn->early.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6611,7 +6855,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = &conn->pktns; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6621,7 +6865,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, hp = &pktns->crypto.ctx.hp; nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen, - (size_t)nread, ckm, hp_key, hp_mask); + (size_t)nread, ckm, hp_ctx, hp_mask); if (nwrite < 0) { if (ngtcp2_err_is_fatal((int)nwrite)) { return nwrite; @@ -6993,7 +7237,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } } - rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num); + rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, pkt_ts); if (rv != 0) { return rv; } @@ -7287,8 +7531,9 @@ static int conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, * packet buffered, perform address validation in order to buffer * validated data only. */ - if (ngtcp2_rob_first_gap_offset(&conn->in_pktns->crypto.strm.rx.rob) == 0) { - if (ngtcp2_rob_data_buffered(&conn->in_pktns->crypto.strm.rx.rob)) { + if (ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0) { + if (conn->in_pktns->crypto.strm.rx.rob && + ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob)) { /* Address has been validated with token */ if (conn->local.settings.token.len) { return 0; @@ -7386,6 +7631,8 @@ static int conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, return rv; } + conn->pktns.rtb.persistent_congestion_start_ts = ts; + /* Re-arm loss detection timer here after handshake has been confirmed. */ ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -7482,8 +7729,8 @@ static size_t conn_server_hs_tx_left(ngtcp2_conn *conn) { static ngtcp2_ssize conn_retransmit_retry_early(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts) { - return conn_write_pkt(conn, dest, destlen, NULL, NGTCP2_PKT_0RTT, NULL, 0, - NULL, 0, NGTCP2_WRITE_PKT_FLAG_NONE, ts); + return conn_write_pkt(conn, dest, destlen, NULL, NGTCP2_PKT_0RTT, + NGTCP2_WRITE_PKT_FLAG_NONE, ts); } /* @@ -7628,6 +7875,11 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, paddr = &conn->remote.transport_params.preferred_address; dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused); ngtcp2_dcid_init(dcid, 1, &paddr->cid, paddr->stateless_reset_token); + + rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1); + if (rv != 0) { + return (ngtcp2_ssize)rv; + } } if (conn->remote.transport_params.stateless_reset_token_present) { @@ -7649,13 +7901,6 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, return (ngtcp2_ssize)rv; } - if (conn->remote.transport_params.preferred_address_present) { - rv = conn_select_preferred_addr(conn); - if (rv != 0) { - return rv; - } - } - cstat->bytes_sent += (size_t)res; return res; @@ -7728,14 +7973,15 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, * `conn_client_write_handshake` writes client side handshake data and * 0RTT packet. * - * |stream_id|, |fin|, |datav|, and |datavcnt| are stream identifier - * to which 0-RTT data is sent, whether it is a last data chunk in - * this stream, a vector of 0-RTT data, and its number of elements - * respectively. If there is no 0RTT data to send, pass negative - * integer to |stream_id|. The amount of 0RTT data sent is assigned - * to |*pdatalen|. If no data is sent, -1 is assigned. Note that 0 - * length STREAM frame is allowed in QUIC, so 0 might be assigned to - * |*pdatalen|. + * In order to send STREAM data in 0RTT packet, specify + * |vmsg|->stream. |vmsg|->stream.strm, |vmsg|->stream.fin, + * |vmsg|->stream.data, and |vmsg|->stream.datacnt are stream to which + * 0-RTT data is sent, whether it is a last data chunk in this stream, + * a vector of 0-RTT data, and its number of elements respectively. + * The amount of 0RTT data sent is assigned to + * *|vmsg|->stream.pdatalen. If no data is sent, -1 is assigned. + * Note that 0 length STREAM frame is allowed in QUIC, so 0 might be + * assigned to *|vmsg|->stream.pdatalen. * * This function returns 0 if it cannot write any frame because buffer * is too small, or packet is congestion limited. Application should @@ -7745,16 +7991,14 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, * pointed by |dest| if it succeeds, or one of the following negative * error codes: (TBD). */ -static ngtcp2_ssize -conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, - ngtcp2_ssize *pdatalen, uint32_t flags, - int64_t stream_id, int fin, const ngtcp2_vec *datav, - size_t datavcnt, ngtcp2_tstamp ts) { - ngtcp2_strm *strm = NULL; +static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, + uint8_t *dest, size_t destlen, + ngtcp2_vmsg *vmsg, + ngtcp2_tstamp ts) { int send_stream = 0; ngtcp2_ssize spktlen, early_spktlen; int was_client_initial; - size_t datalen = ngtcp2_vec_len(datav, datavcnt); + size_t datalen; size_t early_datalen = 0; uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE; int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; @@ -7763,35 +8007,26 @@ conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, /* conn->early.ckm might be created in the first call of conn_handshake(). Check it later. */ - if (stream_id != -1 && + if (vmsg && vmsg->type == NGTCP2_VMSG_TYPE_STREAM && !(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) { - strm = ngtcp2_conn_find_stream(conn, stream_id); - if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; - } - - if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) { - return NGTCP2_ERR_STREAM_SHUT_WR; - } - - send_stream = conn_retry_early_payloadlen(conn) == 0 && - /* 0 length STREAM frame is allowed */ - (datalen == 0 || - (datalen > 0 && (strm->tx.max_offset - strm->tx.offset) && - (conn->tx.max_offset - conn->tx.offset))); + datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); + send_stream = + conn_retry_early_payloadlen(conn) == 0 && + /* 0 length STREAM frame is allowed */ + (datalen == 0 || + (datalen > 0 && + (vmsg->stream.strm->tx.max_offset - vmsg->stream.strm->tx.offset) && + (conn->tx.max_offset - conn->tx.offset))); if (send_stream) { - early_datalen = (size_t)ngtcp2_min((uint64_t)datalen, - strm->tx.max_offset - strm->tx.offset); early_datalen = - (size_t)ngtcp2_min((uint64_t)early_datalen, - conn->tx.max_offset - conn->tx.offset) + + conn_enforce_flow_control(conn, vmsg->stream.strm, datalen) + NGTCP2_STREAM_OVERHEAD; - if (flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { - wflags |= NGTCP2_WRITE_PKT_FLAG_STREAM_MORE; + if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { + wflags |= NGTCP2_WRITE_PKT_FLAG_MORE; } } else { - strm = NULL; + vmsg = NULL; } } @@ -7828,14 +8063,14 @@ conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, return spktlen; } - early_spktlen = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_0RTT, - strm, fin, datav, datavcnt, wflags, ts); + early_spktlen = + conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_0RTT, wflags, ts); if (early_spktlen < 0) { switch (early_spktlen) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: return spktlen; - case NGTCP2_ERR_WRITE_STREAM_MORE: + case NGTCP2_ERR_WRITE_MORE: conn->pkt.was_client_initial = was_client_initial; conn->pkt.hs_spktlen = spktlen; break; @@ -7928,155 +8163,162 @@ size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn) { return conn->crypto.aead_overhead; } -int ngtcp2_conn_install_initial_key(ngtcp2_conn *conn, const uint8_t *rx_key, - const uint8_t *rx_iv, - const uint8_t *rx_hp_key, - const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_initial_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx, + const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx, + const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv, + const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen) { ngtcp2_pktns *pktns = conn->in_pktns; int rv; assert(pktns); - if (pktns->crypto.rx.hp_key) { - ngtcp2_vec_del(pktns->crypto.rx.hp_key, conn->mem); - pktns->crypto.rx.hp_key = NULL; - } + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx); + pktns->crypto.rx.hp_ctx.native_handle = NULL; + if (pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; } - if (pktns->crypto.tx.hp_key) { - ngtcp2_vec_del(pktns->crypto.tx.hp_key, conn->mem); - pktns->crypto.tx.hp_key = NULL; - } + + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx); + pktns->crypto.tx.hp_ctx.native_handle = NULL; + if (pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; } - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, rx_key, keylen, - rx_iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, NULL, rx_iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, rx_hp_key, keylen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, tx_key, keylen, - tx_iv, ivlen, conn->mem); - if (rv != 0) { - return rv; - } + /* Take owner ship after we are sure that no failure occurs, so that + caller can delete these contexts on failure. */ + pktns->crypto.rx.ckm->aead_ctx = *rx_aead_ctx; + pktns->crypto.rx.hp_ctx = *rx_hp_ctx; + pktns->crypto.tx.ckm->aead_ctx = *tx_aead_ctx; + pktns->crypto.tx.hp_ctx = *tx_hp_ctx; - return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem); + return 0; } -int ngtcp2_conn_install_rx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_rx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = conn->hs_pktns; int rv; assert(pktns); - assert(!pktns->crypto.rx.hp_key); + assert(!pktns->crypto.rx.hp_ctx.native_handle); assert(!pktns->crypto.rx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, key, keylen, iv, - ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, aead_ctx, iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); + pktns->crypto.rx.hp_ctx = *hp_ctx; + + return 0; } -int ngtcp2_conn_install_tx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_tx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = conn->hs_pktns; int rv; assert(pktns); - assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.hp_ctx.native_handle); assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, key, keylen, iv, - ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, aead_ctx, iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); + pktns->crypto.tx.hp_ctx = *hp_ctx; + + if (conn->server) { + return ngtcp2_conn_commit_local_transport_params(conn); + } + + return 0; } -int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, const uint8_t *hp_key, - size_t keylen, size_t ivlen) { +int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { int rv; - assert(!conn->early.hp_key); + assert(!conn->early.hp_ctx.native_handle); assert(!conn->early.ckm); - rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, key, keylen, iv, ivlen, + rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, aead_ctx, iv, ivlen, conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&conn->early.hp_key, hp_key, keylen, conn->mem); + conn->early.hp_ctx = *hp_ctx; + + return 0; } int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen) { + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = &conn->pktns; int rv; - assert(!pktns->crypto.rx.hp_key); + assert(!pktns->crypto.rx.hp_ctx.native_handle); assert(!pktns->crypto.rx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, key, - keylen, iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, aead_ctx, + iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); - if (rv != 0) { - return rv; - } + pktns->crypto.rx.hp_ctx = *hp_ctx; return 0; } int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen) { + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = &conn->pktns; int rv; - assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.hp_ctx.native_handle); assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, key, - keylen, iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, aead_ctx, + iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); - if (rv != 0) { - return rv; - } + pktns->crypto.tx.hp_ctx = *hp_ctx; conn->remote.transport_params = conn->remote.pending_transport_params; conn_sync_stream_id_limit(conn); @@ -8150,8 +8392,10 @@ ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) { ngtcp2_tstamp t1 = ngtcp2_conn_loss_detection_expiry(conn); ngtcp2_tstamp t2 = ngtcp2_conn_ack_delay_expiry(conn); ngtcp2_tstamp t3 = ngtcp2_conn_internal_expiry(conn); + ngtcp2_tstamp t4 = ngtcp2_conn_lost_pkt_expiry(conn); ngtcp2_tstamp res = ngtcp2_min(t1, t2); - return ngtcp2_min(res, t3); + res = ngtcp2_min(res, t3); + return ngtcp2_min(res, t4); } int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { @@ -8159,6 +8403,8 @@ int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_conn_cancel_expired_ack_delay_timer(conn, ts); + ngtcp2_conn_remove_lost_pkt(conn, ts); + if (ngtcp2_conn_loss_detection_expiry(conn) <= ts) { rv = ngtcp2_conn_on_loss_detection_timer(conn, ts); if (rv != 0) { @@ -8188,6 +8434,49 @@ void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, acktr_cancel_expired_ack_delay_timer(&conn->pktns.acktr, ts); } +ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) { + ngtcp2_tstamp res = UINT64_MAX, ts; + + if (conn->in_pktns) { + ts = ngtcp2_rtb_lost_pkt_ts(&conn->in_pktns->rtb); + if (ts != UINT64_MAX) { + ts += conn_compute_pto(conn, conn->in_pktns); + res = ngtcp2_min(res, ts); + } + } + + if (conn->hs_pktns) { + ts = ngtcp2_rtb_lost_pkt_ts(&conn->hs_pktns->rtb); + if (ts != UINT64_MAX) { + ts += conn_compute_pto(conn, conn->hs_pktns); + res = ngtcp2_min(res, ts); + } + } + + ts = ngtcp2_rtb_lost_pkt_ts(&conn->pktns.rtb); + if (ts != UINT64_MAX) { + ts += conn_compute_pto(conn, &conn->pktns); + res = ngtcp2_min(res, ts); + } + + return res; +} + +void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + ngtcp2_tstamp pto; + + if (conn->in_pktns) { + pto = conn_compute_pto(conn, conn->in_pktns); + ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, pto, ts); + } + if (conn->hs_pktns) { + pto = conn_compute_pto(conn, conn->hs_pktns); + ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, pto, ts); + } + pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, pto, ts); +} + /* * conn_client_validate_transport_params validates |params| as client. * |params| must be sent with Encrypted Extensions. @@ -8262,7 +8551,7 @@ int ngtcp2_conn_set_remote_transport_params( params); ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, - /* local = */ 0); + NGTCP2_QLOG_SIDE_REMOTE); if (conn->pktns.crypto.tx.ckm) { conn->remote.transport_params = *params; @@ -8308,20 +8597,86 @@ void ngtcp2_conn_set_early_remote_transport_params( conn->tx.max_offset = p->initial_max_data; ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, conn->server, - /* local = */ 0); + NGTCP2_QLOG_SIDE_REMOTE); +} + +int ngtcp2_conn_set_local_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params) { + assert(conn->server); + assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); + + if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) { + return NGTCP2_ERR_INVALID_STATE; + } + + conn->local.settings.transport_params = *params; + + return 0; +} + +int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) { + const ngtcp2_mem *mem = conn->mem; + ngtcp2_transport_params *params = &conn->local.settings.transport_params; + ngtcp2_scid *scident; + ngtcp2_ksl_it it; + int rv; + + assert(1 == ngtcp2_ksl_len(&conn->scid.set)); + + if (params->active_connection_id_limit == 0) { + params->active_connection_id_limit = + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + } + + params->initial_scid = conn->oscid; + + if (conn->oscid.datalen == 0) { + params->preferred_address_present = 0; + } + + if (conn->server) { + if (params->stateless_reset_token_present) { + it = ngtcp2_ksl_begin(&conn->scid.set); + scident = ngtcp2_ksl_it_get(&it); + + memcpy(scident->token, params->stateless_reset_token, + NGTCP2_STATELESS_RESET_TOKENLEN); + } + + if (params->preferred_address_present) { + scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); + if (scident == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid, + params->preferred_address.stateless_reset_token); + + rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident); + if (rv != 0) { + ngtcp2_mem_free(mem, scident); + return rv; + } + + conn->scid.last_seq = 1; + } + } + + conn->rx.unsent_max_offset = conn->rx.max_offset = params->initial_max_data; + conn->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi; + conn->remote.bidi.max_streams = params->initial_max_streams_bidi; + conn->remote.uni.unsent_max_streams = params->initial_max_streams_uni; + conn->remote.uni.max_streams = params->initial_max_streams_uni; + + ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, + NGTCP2_QLOG_SIDE_LOCAL); + + return 0; } void ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn, ngtcp2_transport_params *params) { *params = conn->local.settings.transport_params; - - /* If params->retry_scid_present is set by application then it - should also specify original_dcid because the destination - connection ID from client after Retry is not what we want - here. */ - if (conn->server && !params->retry_scid_present) { - params->original_dcid = conn->rcid; - } } int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -8410,7 +8765,41 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, int64_t stream_id, const ngtcp2_vec *datav, size_t datavcnt, ngtcp2_tstamp ts) { - ngtcp2_strm *strm = NULL; + ngtcp2_vmsg vmsg, *pvmsg; + ngtcp2_strm *strm; + + if (pdatalen) { + *pdatalen = -1; + } + + if (stream_id != -1) { + strm = ngtcp2_conn_find_stream(conn, stream_id); + if (strm == NULL) { + return NGTCP2_ERR_STREAM_NOT_FOUND; + } + + if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) { + return NGTCP2_ERR_STREAM_SHUT_WR; + } + + vmsg.type = NGTCP2_VMSG_TYPE_STREAM; + vmsg.stream.strm = strm; + vmsg.stream.flags = flags; + vmsg.stream.data = datav; + vmsg.stream.datacnt = datavcnt; + vmsg.stream.pdatalen = pdatalen; + + pvmsg = &vmsg; + } else { + pvmsg = NULL; + } + + return ngtcp2_conn_write_vmsg(conn, path, dest, destlen, pvmsg, ts); +} + +ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, + uint8_t *dest, size_t destlen, + ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) { ngtcp2_ssize nwrite; ngtcp2_pktns *pktns = &conn->pktns; size_t origlen = destlen; @@ -8419,15 +8808,10 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; ngtcp2_ssize res = 0; size_t server_hs_tx_left; - int fin = flags & NGTCP2_WRITE_STREAM_FLAG_FIN; conn->log.last_ts = ts; conn->qlog.last_ts = ts; - if (pdatalen) { - *pdatalen = -1; - } - if (path) { ngtcp2_path_copy(path, &conn->dcid.current.ps.path); } @@ -8436,8 +8820,7 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: - nwrite = conn_client_write_handshake(conn, dest, destlen, pdatalen, flags, - stream_id, fin, datav, datavcnt, ts); + nwrite = conn_client_write_handshake(conn, dest, destlen, vmsg, ts); if (nwrite < 0 || conn->state != NGTCP2_CS_POST_HANDSHAKE) { return nwrite; } @@ -8494,18 +8877,15 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, return rv; } - if (stream_id != -1) { - strm = ngtcp2_conn_find_stream(conn, stream_id); - if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; - } - - if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) { - return NGTCP2_ERR_STREAM_SHUT_WR; - } - - if (flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { - wflags |= NGTCP2_WRITE_PKT_FLAG_STREAM_MORE; + if (vmsg) { + switch (vmsg->type) { + case NGTCP2_VMSG_TYPE_STREAM: + if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { + wflags |= NGTCP2_WRITE_PKT_FLAG_MORE; + } + break; + default: + break; } } @@ -8514,8 +8894,8 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, conn->pkt.hs_spktlen = 0; /* dest and destlen have already been adjusted in ppe in the first run. They are adjusted for probe packet later. */ - nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, - strm, fin, datav, datavcnt, wflags, ts); + nwrite = + conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts); goto fin; } else { if (conn->state == NGTCP2_CS_POST_HANDSHAKE) { @@ -8557,14 +8937,14 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, "transmit probe pkt left=%zu", conn->pktns.rtb.probe_pkt_left); - nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, - strm, fin, datav, datavcnt, wflags, ts); + nwrite = + conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts); goto fin; } - nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, strm, - fin, datav, datavcnt, wflags, ts); + nwrite = + conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts); if (nwrite) { assert(nwrite != NGTCP2_ERR_NOBUF); goto fin; @@ -8590,36 +8970,15 @@ fin: return nwrite; } -ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, - ngtcp2_path *path, +static ngtcp2_ssize conn_write_connection_close(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, + uint8_t pkt_type, uint64_t error_code, ngtcp2_tstamp ts) { ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; ngtcp2_ssize res = 0, nwrite; ngtcp2_frame fr; - uint8_t pkt_type; - - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - - if (conn_check_pkt_num_exhausted(conn)) { - return NGTCP2_ERR_PKT_NUM_EXHAUSTED; - } - - switch (conn->state) { - case NGTCP2_CS_CLIENT_INITIAL: - case NGTCP2_CS_CLOSING: - case NGTCP2_CS_DRAINING: - return NGTCP2_ERR_INVALID_STATE; - default: - break; - } - - if (path) { - ngtcp2_path_copy(path, &conn->dcid.current.ps.path); - } fr.type = NGTCP2_FRAME_CONNECTION_CLOSE; fr.connection_close.error_code = error_code; @@ -8627,18 +8986,6 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, fr.connection_close.reasonlen = 0; fr.connection_close.reason = NULL; - if (conn->state == NGTCP2_CS_POST_HANDSHAKE) { - pkt_type = NGTCP2_PKT_SHORT; - } else if (hs_pktns && hs_pktns->crypto.tx.ckm) { - pkt_type = NGTCP2_PKT_HANDSHAKE; - } else if (in_pktns && in_pktns->crypto.tx.ckm) { - pkt_type = NGTCP2_PKT_INITIAL; - } else { - /* This branch is taken if server has not read any Initial packet - from client. */ - return NGTCP2_ERR_INVALID_STATE; - } - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && pkt_type != NGTCP2_PKT_INITIAL) { if (in_pktns && conn->server) { @@ -8683,9 +9030,61 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, return NGTCP2_ERR_NOBUF; } + return res; +} + +ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, + ngtcp2_path *path, + uint8_t *dest, size_t destlen, + uint64_t error_code, + ngtcp2_tstamp ts) { + ngtcp2_pktns *in_pktns = conn->in_pktns; + ngtcp2_pktns *hs_pktns = conn->hs_pktns; + uint8_t pkt_type; + ngtcp2_ssize nwrite; + + conn->log.last_ts = ts; + conn->qlog.last_ts = ts; + + if (conn_check_pkt_num_exhausted(conn)) { + return NGTCP2_ERR_PKT_NUM_EXHAUSTED; + } + + switch (conn->state) { + case NGTCP2_CS_CLIENT_INITIAL: + case NGTCP2_CS_CLOSING: + case NGTCP2_CS_DRAINING: + return NGTCP2_ERR_INVALID_STATE; + default: + break; + } + + if (path) { + ngtcp2_path_copy(path, &conn->dcid.current.ps.path); + } + + if (conn->state == NGTCP2_CS_POST_HANDSHAKE || + (conn->server && conn->pktns.crypto.tx.ckm)) { + pkt_type = NGTCP2_PKT_SHORT; + } else if (hs_pktns && hs_pktns->crypto.tx.ckm) { + pkt_type = NGTCP2_PKT_HANDSHAKE; + } else if (in_pktns && in_pktns->crypto.tx.ckm) { + pkt_type = NGTCP2_PKT_INITIAL; + } else { + /* This branch is taken if server has not read any Initial packet + from client. */ + return NGTCP2_ERR_INVALID_STATE; + } + + nwrite = conn_write_connection_close(conn, dest, destlen, pkt_type, + error_code, ts); + if (nwrite < 0) { + return nwrite; + } + conn->state = NGTCP2_CS_CLOSING; - return res; + return nwrite; } ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn, @@ -8694,6 +9093,7 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn, uint64_t app_error_code, ngtcp2_tstamp ts) { ngtcp2_ssize nwrite; + ngtcp2_ssize res = 0; ngtcp2_frame fr; conn->log.last_ts = ts; @@ -8704,12 +9104,38 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn, } switch (conn->state) { - case NGTCP2_CS_POST_HANDSHAKE: - break; - default: + case NGTCP2_CS_CLIENT_INITIAL: + case NGTCP2_CS_CLOSING: + case NGTCP2_CS_DRAINING: return NGTCP2_ERR_INVALID_STATE; + default: + break; + } + + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) { + nwrite = conn_write_connection_close(conn, dest, destlen, + conn->hs_pktns->crypto.tx.ckm + ? NGTCP2_PKT_HANDSHAKE + : NGTCP2_PKT_INITIAL, + NGTCP2_APPLICATION_ERROR, ts); + if (nwrite < 0) { + return nwrite; + } + res = nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; } + if (conn->state != NGTCP2_CS_POST_HANDSHAKE) { + assert(res); + + if (!conn->server || !conn->pktns.crypto.tx.ckm) { + return res; + } + } + + assert(conn->pktns.crypto.tx.ckm); + if (path) { ngtcp2_path_copy(path, &conn->dcid.current.ps.path); } @@ -8728,13 +9154,15 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn, return nwrite; } - if (nwrite == 0) { + res += nwrite; + + if (res == 0) { return NGTCP2_ERR_NOBUF; } conn->state = NGTCP2_CS_CLOSING; - return nwrite; + return res; } int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn) { @@ -8780,7 +9208,7 @@ int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm, if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RDWR) == NGTCP2_STRM_FLAG_SHUT_RDWR && ((strm->flags & NGTCP2_STRM_FLAG_RECV_RST) || - ngtcp2_rob_first_gap_offset(&strm->rx.rob) == strm->rx.last_offset) && + ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) && (((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) && (strm->flags & NGTCP2_STRM_FLAG_RST_ACKED)) || (!(strm->flags & NGTCP2_STRM_FLAG_SENT_RST) && @@ -8974,17 +9402,12 @@ uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn) { int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_rtb *rtb = &conn->pktns.rtb; - ngtcp2_frame_chain *frc = NULL; int rv; conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED; - ngtcp2_rtb_remove_all(rtb, &frc, &conn->cstat); - - rv = conn_resched_frames(conn, pktns, &frc); + rv = ngtcp2_rtb_remove_all(rtb, conn, pktns, &conn->cstat); if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } @@ -8997,8 +9420,9 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, rtt = ngtcp2_max(rtt, NGTCP2_GRANULARITY); + cstat->latest_rtt = rtt; + if (cstat->min_rtt == UINT64_MAX) { - cstat->latest_rtt = rtt; cstat->min_rtt = rtt; cstat->smoothed_rtt = rtt; cstat->rttvar = rtt / 2; @@ -9014,8 +9438,6 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, rtt -= ack_delay; } - cstat->latest_rtt = rtt; - cstat->rttvar = (cstat->rttvar * 3 + (cstat->smoothed_rtt < rtt ? rtt - cstat->smoothed_rtt : cstat->smoothed_rtt - rtt)) / @@ -9047,7 +9469,7 @@ static ngtcp2_pktns *conn_get_earliest_pktns(ngtcp2_conn *conn, ngtcp2_tstamp earliest_ts = times[NGTCP2_PKTNS_ID_INITIAL]; for (i = NGTCP2_PKTNS_ID_HANDSHAKE; i < NGTCP2_PKTNS_ID_MAX; ++i) { - if (ns[i] == NULL || ns[i]->rtb.num_ack_eliciting == 0 || + if (ns[i] == NULL || ns[i]->rtb.num_retransmittable == 0 || (times[i] == UINT64_MAX || (earliest_ts != UINT64_MAX && times[i] >= earliest_ts) || (i == NGTCP2_PKTNS_ID_APP && @@ -9096,9 +9518,9 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return; } - if ((!in_pktns || in_pktns->rtb.num_ack_eliciting == 0) && - (!hs_pktns || hs_pktns->rtb.num_ack_eliciting == 0) && - (pktns->rtb.num_ack_eliciting == 0 || + if ((!in_pktns || in_pktns->rtb.num_retransmittable == 0) && + (!hs_pktns || hs_pktns->rtb.num_retransmittable == 0) && + (pktns->rtb.num_retransmittable == 0 || !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) && (conn->server || (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | @@ -9132,36 +9554,6 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { (uint64_t)(timeout / NGTCP2_MILLISECONDS)); } -/* - * conn_on_crypto_timeout is called when handshake packets which - * belong to |pktns| are lost. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int conn_on_crypto_timeout(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { - ngtcp2_frame_chain *frc = NULL; - int rv; - - rv = ngtcp2_rtb_on_crypto_timeout(&pktns->rtb, &frc, &conn->cstat); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_list_del(frc, conn->mem); - return rv; - } - - rv = conn_resched_frames(conn, pktns, &frc); - if (rv != 0) { - ngtcp2_frame_chain_list_del(frc, conn->mem); - return rv; - } - - return 0; -} - int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_conn_stat *cstat = &conn->cstat; int rv; @@ -9203,16 +9595,8 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if (!conn->server && !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { if (hs_pktns->crypto.tx.ckm) { - rv = conn_on_crypto_timeout(conn, hs_pktns); - if (rv != 0) { - return rv; - } hs_pktns->rtb.probe_pkt_left = 1; } else { - rv = conn_on_crypto_timeout(conn, in_pktns); - if (rv != 0) { - return rv; - } in_pktns->rtb.probe_pkt_left = 1; } } else { @@ -9223,10 +9607,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { switch (earliest_pktns->rtb.pktns_id) { case NGTCP2_PKTNS_ID_INITIAL: assert(in_pktns); - rv = conn_on_crypto_timeout(conn, in_pktns); - if (rv != 0) { - return rv; - } in_pktns->rtb.probe_pkt_left = 1; if (!conn->server) { break; @@ -9235,10 +9615,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { /* fall through */ case NGTCP2_PKTNS_ID_HANDSHAKE: assert(hs_pktns); - rv = conn_on_crypto_timeout(conn, hs_pktns); - if (rv != 0) { - return rv; - } hs_pktns->rtb.probe_pkt_left = 1; break; case NGTCP2_PKTNS_ID_APP: @@ -9580,8 +9956,12 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn) { } void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, - const ngtcp2_crypto_aead *aead) { + const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx) { + assert(!conn->crypto.retry_aead_ctx.native_handle); + conn->crypto.retry_aead = *aead; + conn->crypto.retry_aead_ctx = *aead_ctx; } void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, @@ -9623,6 +10003,23 @@ int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) { int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; } +int ngtcp2_conn_after_retry(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) != 0; +} + +int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id, + void *stream_user_data) { + ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); + + if (strm == NULL) { + return NGTCP2_ERR_STREAM_NOT_FOUND; + } + + strm->stream_user_data = stream_user_data; + + return 0; +} + void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const uint8_t *data) { memcpy(pcent->data, data, sizeof(pcent->data)); @@ -9631,6 +10028,7 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, void ngtcp2_settings_default(ngtcp2_settings *settings) { memset(settings, 0, sizeof(*settings)); settings->cc_algo = NGTCP2_CC_ALGO_CUBIC; + settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT; settings->transport_params.max_udp_payload_size = NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE; settings->transport_params.ack_delay_exponent = @@ -9647,13 +10045,12 @@ void ngtcp2_settings_default(ngtcp2_settings *settings) { ngtcp2_ssize ngtcp2_pkt_write_connection_close( uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, uint64_t error_code, ngtcp2_encrypt encrypt, - const ngtcp2_crypto_aead *aead, const uint8_t *key, const uint8_t *iv, - ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key) { + const ngtcp2_crypto_aead *aead, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pkt_hd hd; ngtcp2_crypto_km ckm; ngtcp2_crypto_cc cc; - ngtcp2_vec hp_key_vec; ngtcp2_ppe ppe; ngtcp2_frame fr = {0}; int rv; @@ -9663,9 +10060,8 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( NGTCP2_PROTO_VER, /* len = */ 0); ngtcp2_vec_init(&ckm.secret, NULL, 0); - ngtcp2_vec_init(&ckm.key, key, 16); ngtcp2_vec_init(&ckm.iv, iv, 12); - ngtcp2_vec_init(&hp_key_vec, hp_key, 16); + ckm.aead_ctx = *aead_ctx; ckm.pkt_num = 0; ckm.flags = NGTCP2_CRYPTO_KM_FLAG_NONE; @@ -9673,7 +10069,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( cc.aead = *aead; cc.hp = *hp; cc.ckm = &ckm; - cc.hp_key = &hp_key_vec; + cc.hp_ctx = *hp_ctx; cc.encrypt = encrypt; cc.hp_mask = hp_mask; |