MEDIUM: quic: Retransmission functions rework
qc_prep_fast_retrans() and qc_prep_hdshk_fast_retrans() are modified to
take two list of frames as parameters. Two lists are needed for
qc_prep_hdshk_fast_retrans() to build datagrams with two packets during
handshake. qc_prep_fast_retrans() needs two lists of frames to be used
to send two datagrams with one list by datagram.
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 1924579..9eac26f 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -2442,22 +2442,24 @@
}
/* Prepare a fast retransmission from <qel> encryption level */
-static void qc_prep_fast_retrans(struct quic_enc_level *qel,
- struct quic_conn *qc)
+static void qc_prep_fast_retrans(struct quic_conn *qc,
+ struct quic_enc_level *qel,
+ struct list *frms1, struct list *frms2)
{
struct eb_root *pkts = &qel->pktns->tx.pkts;
+ struct list *frms = frms1;
struct eb64_node *node;
struct quic_tx_packet *pkt;
pkt = NULL;
- pkts = &qel->pktns->tx.pkts;
node = eb64_first(pkts);
- /* Skip the empty packet (they have already been retransmitted) */
+ start:
while (node) {
- pkt = eb64_entry(&node->node, struct quic_tx_packet, pn_node);
+ pkt = eb64_entry(node, struct quic_tx_packet, pn_node);
+ node = eb64_next(node);
+ /* Skip the empty and coalesced packets */
if (!LIST_ISEMPTY(&pkt->frms) && !(pkt->flags & QUIC_FL_TX_PACKET_COALESCED))
break;
- node = eb64_next(node);
}
if (!pkt)
@@ -2472,20 +2474,24 @@
return;
}
- qc_requeue_nacked_pkt_tx_frms(qc, &pkt->frms, &qel->pktns->tx.frms);
+ TRACE_PROTO("duplicating packet", QUIC_EV_CONN_PRSAFRM, qc, NULL, &pkt->pn_node.key);
+ qc_dup_pkt_frms(qc, &pkt->frms, frms);
+ if (frms == frms1 && frms2) {
+ frms = frms2;
+ goto start;
+ }
}
-/* Prepare a fast retransmission during handshake after a client
+/* Prepare a fast retransmission during a handshake after a client
* has resent Initial packets. According to the RFC a server may retransmit
- * up to two datagrams of Initial packets if did not receive all Initial packets
- * and resend them coalescing with others (Handshake here).
- * (Listener only).
+ * Initial packets send them coalescing with others (Handshake here).
+ * (Listener only function).
*/
-static void qc_prep_hdshk_fast_retrans(struct quic_conn *qc)
+static void qc_prep_hdshk_fast_retrans(struct quic_conn *qc,
+ struct list *ifrms, struct list *hfrms)
{
struct list itmp = LIST_HEAD_INIT(itmp);
struct list htmp = LIST_HEAD_INIT(htmp);
- struct quic_frame *frm, *frmbak;
struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL];
struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE];
@@ -2495,15 +2501,6 @@
struct quic_tx_packet *pkt;
struct list *tmp = &itmp;
- /* Do not probe from a packet number space if some probing
- * was already asked.
- */
- if (qel->pktns->tx.pto_probe) {
- qel = hqel;
- if (qel->pktns->tx.pto_probe)
- return;
- }
-
start:
pkt = NULL;
pkts = &qel->pktns->tx.pkts;
@@ -2530,21 +2527,8 @@
qel->pktns->tx.pto_probe += 1;
requeue:
- list_for_each_entry_safe(frm, frmbak, &pkt->frms, list) {
- struct quic_frame *dup_frm;
-
-
- dup_frm = pool_alloc(pool_head_quic_frame);
- if (!dup_frm) {
- TRACE_PROTO("could not duplicate frame", QUIC_EV_CONN_PRSAFRM, qc, frm);
- break;
- }
-
- TRACE_PROTO("to resend frame", QUIC_EV_CONN_PRSAFRM, qc, frm);
- *dup_frm = *frm;
- LIST_APPEND(tmp, &dup_frm->list);
- }
-
+ TRACE_PROTO("duplicating packet", QUIC_EV_CONN_PRSAFRM, qc, NULL, &pkt->pn_node.key);
+ qc_dup_pkt_frms(qc, &pkt->frms, tmp);
if (qel == iqel) {
if (pkt->next && pkt->next->type == QUIC_PACKET_TYPE_HANDSHAKE) {
pkt = pkt->next;
@@ -2552,15 +2536,11 @@
hqel->pktns->tx.pto_probe += 1;
goto requeue;
}
-
- qel = hqel;
- tmp = &htmp;
- goto start;
}
end:
- LIST_SPLICE(&iqel->pktns->tx.frms, &itmp);
- LIST_SPLICE(&hqel->pktns->tx.frms, &htmp);
+ LIST_SPLICE(ifrms, &itmp);
+ LIST_SPLICE(hfrms, &htmp);
}
/* Parse all the frames of <pkt> QUIC packet for QUIC connection with <ctx>
@@ -2761,8 +2741,12 @@
/* Flag this packet number space as having received a packet. */
qel->pktns->flags |= QUIC_FL_PKTNS_PKT_RECEIVED;
- if (fast_retrans)
- qc_prep_hdshk_fast_retrans(qc);
+ if (fast_retrans) {
+ struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL];
+ struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE];
+
+ qc_prep_hdshk_fast_retrans(qc, &iqel->pktns->tx.frms, &hqel->pktns->tx.frms);
+ }
/* The server must switch from INITIAL to HANDSHAKE handshake state when it
* has successfully parse a Handshake packet. The Initial encryption must also