BUG/MINOR: quic: support FIN on Rx-buffered STREAM frames

FIN flag on a STREAM frame was not detected if the frame was previously
buffered on qcs.rx.frms before being handled.

To fix this, copy the fin field from the quic_stream instance to
quic_rx_strm_frm. This is required to properly notify the FIN flag on
qc_treat_rx_strm_frms for the MUX layer.

Without this fix, the request channel might be left opened after the
last STREAM frame reception if there is out-of-order frames on the Rx
path.
This commit is contained in:
Amaury Denoyelle 2022-02-28 11:38:36 +01:00
parent 3bf06093dc
commit 3c4303998f
2 changed files with 11 additions and 4 deletions

View File

@ -496,6 +496,7 @@ struct quic_rx_strm_frm {
struct eb64_node offset_node; struct eb64_node offset_node;
uint64_t len; uint64_t len;
const unsigned char *data; const unsigned char *data;
int fin;
struct quic_rx_packet *pkt; struct quic_rx_packet *pkt;
}; };

View File

@ -1964,6 +1964,7 @@ struct quic_rx_strm_frm *new_quic_rx_strm_frm(struct quic_stream *stream_frm,
frm->len = stream_frm->len; frm->len = stream_frm->len;
frm->data = stream_frm->data; frm->data = stream_frm->data;
frm->pkt = pkt; frm->pkt = pkt;
frm->fin = stream_frm->fin;
} }
return frm; return frm;
@ -2026,14 +2027,15 @@ static size_t qc_treat_rx_strm_frms(struct qcs *qcs)
size_t diff; size_t diff;
frm = eb64_entry(&frm_node->node, struct quic_rx_strm_frm, offset_node); frm = eb64_entry(&frm_node->node, struct quic_rx_strm_frm, offset_node);
if (frm->offset_node.key > qcs->rx.offset)
break;
if (frm->offset_node.key + frm->len < qcs->rx.offset) { if (frm->offset_node.key + frm->len < qcs->rx.offset) {
/* fully already received STREAM offset */ /* fully already received STREAM offset */
goto next; goto next;
} }
BUG_ON(qcs->flags & QC_SF_FIN_RECV);
if (frm->offset_node.key > qcs->rx.offset)
break;
diff = qcs->rx.offset - frm->offset_node.key; diff = qcs->rx.offset - frm->offset_node.key;
frm->data += diff; frm->data += diff;
frm->len -= diff; frm->len -= diff;
@ -2055,6 +2057,9 @@ static size_t qc_treat_rx_strm_frms(struct qcs *qcs)
break; break;
} }
if (frm->fin)
qcs->flags |= QC_SF_FIN_RECV;
next: next:
frm_node = eb64_next(frm_node); frm_node = eb64_next(frm_node);
quic_rx_packet_refdec(frm->pkt); quic_rx_packet_refdec(frm->pkt);
@ -2117,11 +2122,12 @@ static int qc_handle_bidi_strm_frm(struct quic_rx_packet *pkt,
strm->rx.offset += ret; strm->rx.offset += ret;
} }
total += qc_treat_rx_strm_frms(strm);
/* FIN is set only if all data were copied. */ /* FIN is set only if all data were copied. */
if (strm_frm->fin && !strm_frm->len) if (strm_frm->fin && !strm_frm->len)
strm->flags |= QC_SF_FIN_RECV; strm->flags |= QC_SF_FIN_RECV;
total += qc_treat_rx_strm_frms(strm);
if (total && qc->qcc->app_ops->decode_qcs(strm, strm->flags & QC_SF_FIN_RECV, qc->qcc->ctx) < 0) { if (total && qc->qcc->app_ops->decode_qcs(strm, strm->flags & QC_SF_FIN_RECV, qc->qcc->ctx) < 0) {
TRACE_PROTO("Decoding error", QUIC_EV_CONN_PSTRM, qc); TRACE_PROTO("Decoding error", QUIC_EV_CONN_PSTRM, qc);
return 0; return 0;