diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index 4843a23849286c7b066aa1d6a48ded36ffb6a488..fe150e414878346b972cfc0b5e3b6f14a093c349 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -1366,8 +1366,7 @@ static size_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { ngtcp2_frame_chain *frc; ngtcp2_crypto *fr; - ngtcp2_ksl_it gapit; - ngtcp2_range *gap; + ngtcp2_range gap; ngtcp2_rtb *rtb = &pktns->rtb; ngtcp2_ksl_it it; size_t datalen; @@ -1379,17 +1378,15 @@ static size_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn, frc = ngtcp2_ksl_it_get(&it); fr = &frc->fr.crypto; - gapit = ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, - fr->offset); - gap = ngtcp2_ksl_it_key(&gapit); + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset); datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - if (gap->begin <= fr->offset) { + if (gap.begin <= fr->offset) { return fr->offset; } - if (gap->begin < fr->offset + datalen) { - return gap->begin; + if (gap.begin < fr->offset + datalen) { + return gap.begin; } } @@ -1403,7 +1400,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; @@ -1422,9 +1418,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; } diff --git a/lib/ngtcp2_rtb.c b/lib/ngtcp2_rtb.c index e7e6762e03daf4b0081f44c88d59c0b3f40f4f8b..926258d900e5e09acd196625c3a632176919d4f6 100644 --- a/lib/ngtcp2_rtb.c +++ b/lib/ngtcp2_rtb.c @@ -289,17 +289,16 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, if (strm == NULL) { break; } - prev_stream_offset = - ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset); - rv = ngtcp2_gaptr_push( - &strm->tx.acked_offset, frc->fr.stream.offset, + prev_stream_offset = ngtcp2_strm_get_acked_offset(strm); + rv = ngtcp2_strm_ack_data( + strm, frc->fr.stream.offset, ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt)); if (rv != 0) { return rv; } if (conn->callbacks.acked_stream_data_offset) { - stream_offset = ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset); + stream_offset = ngtcp2_strm_get_acked_offset(strm); datalen = stream_offset - prev_stream_offset; if (datalen == 0 && !frc->fr.stream.fin) { break; @@ -319,17 +318,16 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, } break; case NGTCP2_FRAME_CRYPTO: - prev_stream_offset = - ngtcp2_gaptr_first_gap_offset(&crypto->tx.acked_offset); - rv = ngtcp2_gaptr_push( - &crypto->tx.acked_offset, frc->fr.crypto.offset, + prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto); + rv = ngtcp2_strm_ack_data( + crypto, frc->fr.crypto.offset, ngtcp2_vec_len(frc->fr.crypto.data, frc->fr.crypto.datacnt)); if (rv != 0) { return rv; } if (conn->callbacks.acked_crypto_offset) { - stream_offset = ngtcp2_gaptr_first_gap_offset(&crypto->tx.acked_offset); + stream_offset = ngtcp2_strm_get_acked_offset(crypto); datalen = stream_offset - prev_stream_offset; if (datalen == 0) { break; @@ -628,7 +626,6 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, ngtcp2_ksl_it it; ngtcp2_frame_chain *nfrc; ngtcp2_frame_chain *frc; - ngtcp2_ksl_it gapit; ngtcp2_range gap, range; ngtcp2_crypto *fr; int all_acked; @@ -654,9 +651,7 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, /* Don't resend CRYPTO frame if the whole region it contains has been acknowledged */ - gapit = ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, - fr->offset); - gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit); + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset); range.begin = fr->offset; range.end = fr->offset + ngtcp2_vec_len(fr->data, fr->datacnt); diff --git a/lib/ngtcp2_strm.c b/lib/ngtcp2_strm.c index 4f88fb30337207cb98e59df224e012d262cc0a93..214683de9d31e30e1db9e5a66dd5f459b18d4bb9 100644 --- a/lib/ngtcp2_strm.c +++ b/lib/ngtcp2_strm.c @@ -39,6 +39,8 @@ int ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, uint64_t max_rx_offset, uint64_t max_tx_offset, void *stream_user_data, const ngtcp2_mem *mem) { strm->cycle = 0; + strm->tx.acked_offset = NULL; + strm->tx.cont_acked_offset = 0; strm->tx.streamfrq = NULL; strm->tx.offset = 0; strm->tx.max_offset = max_tx_offset; @@ -55,7 +57,7 @@ int ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, strm->mem = mem; strm->app_error_code = 0; - return ngtcp2_gaptr_init(&strm->tx.acked_offset, mem); + return 0; } void ngtcp2_strm_free(ngtcp2_strm *strm) { @@ -72,10 +74,13 @@ void ngtcp2_strm_free(ngtcp2_strm *strm) { } ngtcp2_ksl_free(strm->tx.streamfrq); + ngtcp2_mem_free(strm->mem, strm->tx.streamfrq); } ngtcp2_rob_free(strm->rx.rob); - ngtcp2_gaptr_free(&strm->tx.acked_offset); + ngtcp2_mem_free(strm->mem, strm->rx.rob); + ngtcp2_gaptr_free(strm->tx.acked_offset); + ngtcp2_mem_free(strm->mem, strm->tx.acked_offset); } static int strm_rob_init(ngtcp2_strm *strm) { @@ -371,6 +376,77 @@ int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm) { } int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm) { - return ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset) == + if (strm->tx.acked_offset == NULL) { + return strm->tx.cont_acked_offset == strm->tx.offset; + } + + return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset) == strm->tx.offset; } + +ngtcp2_range ngtcp2_strm_get_unacked_range_after(ngtcp2_strm *strm, + uint64_t offset) { + ngtcp2_ksl_it gapit; + ngtcp2_range gap; + + if (strm->tx.acked_offset == NULL) { + gap.begin = strm->tx.cont_acked_offset; + gap.end = UINT64_MAX; + return gap; + } + + gapit = ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset); + return *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit); +} + +uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm) { + if (strm->tx.acked_offset == NULL) { + return strm->tx.cont_acked_offset; + } + + return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset); +} + +static int strm_acked_offset_init(ngtcp2_strm *strm) { + int rv; + ngtcp2_gaptr *acked_offset = + ngtcp2_mem_malloc(strm->mem, sizeof(*acked_offset)); + + if (acked_offset == NULL) { + return NGTCP2_ERR_NOMEM; + } + + rv = ngtcp2_gaptr_init(acked_offset, strm->mem); + if (rv != 0) { + ngtcp2_mem_free(strm->mem, acked_offset); + return rv; + } + + strm->tx.acked_offset = acked_offset; + + return 0; +} + +int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) { + int rv; + + if (strm->tx.acked_offset == NULL) { + if (strm->tx.cont_acked_offset == offset) { + strm->tx.cont_acked_offset += len; + return 0; + } + + rv = strm_acked_offset_init(strm); + if (rv != 0) { + return rv; + } + + rv = + ngtcp2_gaptr_push(strm->tx.acked_offset, 0, strm->tx.cont_acked_offset); + if (rv != 0) { + return rv; + } + } + + return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len); +} diff --git a/lib/ngtcp2_strm.h b/lib/ngtcp2_strm.h index 4d16d4df4b20b3d4e85ea11471b8c08c75d2c845..999c37a63f3318fc6a3aca6633e25e51174c0f1a 100644 --- a/lib/ngtcp2_strm.h +++ b/lib/ngtcp2_strm.h @@ -76,7 +76,12 @@ struct ngtcp2_strm { struct { /* acked_offset tracks acknowledged outgoing data. */ - ngtcp2_gaptr acked_offset; + ngtcp2_gaptr *acked_offset; + /* cont_acked_offset is the offset that all data up to this offset + is acknowledged by a remote endpoint. It is used until the + remote endpoint acknowledges data in out-of-order. After that, + acked_offset is used instead. */ + uint64_t cont_acked_offset; /* streamfrq contains STREAM frame for retransmission. The flow control credits have been paid when they are transmitted first time. There are no restriction regarding flow control for @@ -229,4 +234,24 @@ int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm); */ int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm); +/* + * ngtcp2_strm_get_unacked_range_after returns the range that is not + * acknowledged yet and intersects or comes after |offset|. + */ +ngtcp2_range ngtcp2_strm_get_unacked_range_after(ngtcp2_strm *strm, + uint64_t offset); + +/* + * ngtcp2_strm_get_acked_offset returns offset, that is the data up to + * this offset have been acknowledged by a remote endpoint. It + * returns 0 if no data is acknowledged. + */ +uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm); + +/* + * ngtcp2_strm_ack_data tells |strm| that the data [offset, + * offset+len) is acknowledged by a remote endpoint. + */ +int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len); + #endif /* NGTCP2_STRM_H */